Merge "Expose radio metadata image query APIs as system APIs" into main
diff --git a/AconfigFlags.bp b/AconfigFlags.bp
index beb11fc..98b62b3 100644
--- a/AconfigFlags.bp
+++ b/AconfigFlags.bp
@@ -26,6 +26,7 @@
":android.content.flags-aconfig-java{.generated_srcjars}",
":android.content.pm.flags-aconfig-java{.generated_srcjars}",
":android.content.res.flags-aconfig-java{.generated_srcjars}",
+ ":android.crashrecovery.flags-aconfig-java{.generated_srcjars}",
":android.credentials.flags-aconfig-java{.generated_srcjars}",
":android.database.sqlite-aconfig-java{.generated_srcjars}",
":android.hardware.biometrics.flags-aconfig-java{.generated_srcjars}",
@@ -94,6 +95,7 @@
"android.companion.virtual.flags-aconfig",
"android.content.pm.flags-aconfig",
"android.content.res.flags-aconfig",
+ "android.crashrecovery.flags-aconfig",
"android.credentials.flags-aconfig",
"android.database.sqlite-aconfig",
"android.hardware.biometrics.flags-aconfig",
@@ -1078,3 +1080,16 @@
aconfig_declarations: "android.adaptiveauth.flags-aconfig",
defaults: ["framework-minus-apex-aconfig-java-defaults"],
}
+
+// CrashRecovery Module
+aconfig_declarations {
+ name: "android.crashrecovery.flags-aconfig",
+ package: "android.crashrecovery.flags",
+ srcs: ["packages/CrashRecovery/aconfig/flags.aconfig"],
+}
+
+java_aconfig_library {
+ name: "android.crashrecovery.flags-aconfig-java",
+ aconfig_declarations: "android.crashrecovery.flags-aconfig",
+ defaults: ["framework-minus-apex-aconfig-java-defaults"],
+}
\ No newline at end of file
diff --git a/Android.bp b/Android.bp
index 9c56733..e12f74f 100644
--- a/Android.bp
+++ b/Android.bp
@@ -95,6 +95,7 @@
":platform-compat-native-aidl",
// AIDL sources from external directories
+ ":android.frameworks.location.altitude-V2-java-source",
":android.hardware.biometrics.common-V4-java-source",
":android.hardware.biometrics.fingerprint-V3-java-source",
":android.hardware.biometrics.face-V4-java-source",
diff --git a/apct-tests/perftests/contentcapture/src/android/view/contentcapture/AbstractContentCapturePerfTestCase.java b/apct-tests/perftests/contentcapture/src/android/view/contentcapture/AbstractContentCapturePerfTestCase.java
index 0ea2daf..bc84708 100644
--- a/apct-tests/perftests/contentcapture/src/android/view/contentcapture/AbstractContentCapturePerfTestCase.java
+++ b/apct-tests/perftests/contentcapture/src/android/view/contentcapture/AbstractContentCapturePerfTestCase.java
@@ -248,6 +248,11 @@
return mServiceWatcher.waitOnCreate();
}
+ /** Wait for session paused. */
+ public void waitForSessionPaused() throws InterruptedException {
+ mServiceWatcher.waitSessionPaused();
+ }
+
@NonNull
protected ActivityWatcher startWatcher() {
return mActivitiesWatcher.watch(CustomTestActivity.class);
diff --git a/apct-tests/perftests/contentcapture/src/android/view/contentcapture/LoginTest.java b/apct-tests/perftests/contentcapture/src/android/view/contentcapture/LoginTest.java
index aa95dfd..44e8a67 100644
--- a/apct-tests/perftests/contentcapture/src/android/view/contentcapture/LoginTest.java
+++ b/apct-tests/perftests/contentcapture/src/android/view/contentcapture/LoginTest.java
@@ -80,6 +80,34 @@
testActivityLaunchTime(R.layout.test_container_activity, 500);
}
+ @Test
+ public void testSendEventsLatency() throws Throwable {
+ enableService();
+
+ testSendEventLatency(R.layout.test_container_activity, 0);
+ }
+
+ @Test
+ public void testSendEventsLatency_contains100Views() throws Throwable {
+ enableService();
+
+ testSendEventLatency(R.layout.test_container_activity, 100);
+ }
+
+ @Test
+ public void testSendEventsLatency_contains300Views() throws Throwable {
+ enableService();
+
+ testSendEventLatency(R.layout.test_container_activity, 300);
+ }
+
+ @Test
+ public void testSendEventsLatency_contains500Views() throws Throwable {
+ enableService();
+
+ testSendEventLatency(R.layout.test_container_activity, 500);
+ }
+
private void testActivityLaunchTime(int layoutId, int numViews) throws Throwable {
final Object drawNotifier = new Object();
final Intent intent = getLaunchIntent(layoutId, numViews);
@@ -111,6 +139,38 @@
}
}
+ private void testSendEventLatency(int layoutId, int numViews) throws Throwable {
+ final Object drawNotifier = new Object();
+ final Intent intent = getLaunchIntent(layoutId, numViews);
+ intent.putExtra(CustomTestActivity.INTENT_EXTRA_FINISH_ON_IDLE, true);
+ intent.putExtra(CustomTestActivity.INTENT_EXTRA_DRAW_CALLBACK,
+ new RemoteCallback(result -> {
+ synchronized (drawNotifier) {
+ drawNotifier.notifyAll();
+ }
+ }));
+ final ActivityWatcher watcher = startWatcher();
+
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ mEntryActivity.startActivity(intent);
+ synchronized (drawNotifier) {
+ try {
+ drawNotifier.wait(GENERIC_TIMEOUT_MS);
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ waitForSessionPaused();
+
+ // Ignore the time to finish the activity
+ state.pauseTiming();
+ watcher.waitFor(DESTROYED);
+ sInstrumentation.waitForIdleSync();
+ state.resumeTiming();
+ }
+ }
+
@Test
public void testOnVisibilityAggregated_visibleChanged() throws Throwable {
enableService();
diff --git a/apct-tests/perftests/contentcapture/src/android/view/contentcapture/MyContentCaptureService.java b/apct-tests/perftests/contentcapture/src/android/view/contentcapture/MyContentCaptureService.java
index ecc5112..0b5345f 100644
--- a/apct-tests/perftests/contentcapture/src/android/view/contentcapture/MyContentCaptureService.java
+++ b/apct-tests/perftests/contentcapture/src/android/view/contentcapture/MyContentCaptureService.java
@@ -114,6 +114,10 @@
public void onContentCaptureEvent(ContentCaptureSessionId sessionId,
ContentCaptureEvent event) {
Log.i(TAG, "onContentCaptureEventsRequest(session=" + sessionId + "): " + event);
+ if (sServiceWatcher != null
+ && event.getType() == ContentCaptureEvent.TYPE_SESSION_PAUSED) {
+ sServiceWatcher.mSessionPaused.countDown();
+ }
}
@Override
@@ -126,6 +130,7 @@
private static final long GENERIC_TIMEOUT_MS = 10_000;
private final CountDownLatch mCreated = new CountDownLatch(1);
private final CountDownLatch mDestroyed = new CountDownLatch(1);
+ private final CountDownLatch mSessionPaused = new CountDownLatch(1);
private boolean mReadyToClear = true;
private Pair<Set<String>, Set<ComponentName>> mAllowList;
@@ -151,6 +156,11 @@
await(mDestroyed, "not destroyed");
}
+ /** Wait for session paused. */
+ public void waitSessionPaused() throws InterruptedException {
+ await(mSessionPaused, "no Paused");
+ }
+
/**
* Allow just this package.
*/
diff --git a/apex/jobscheduler/framework/java/com/android/server/job/JobSchedulerInternal.java b/apex/jobscheduler/framework/java/com/android/server/job/JobSchedulerInternal.java
index 6c8af39..ae98fe1 100644
--- a/apex/jobscheduler/framework/java/com/android/server/job/JobSchedulerInternal.java
+++ b/apex/jobscheduler/framework/java/com/android/server/job/JobSchedulerInternal.java
@@ -77,6 +77,12 @@
@NonNull String notificationChannel, int userId, @NonNull String packageName);
/**
+ * @return {@code true} if the given package holds the
+ * {@link android.Manifest.permission.RUN_BACKUP_JOBS} permission.
+ */
+ boolean hasRunBackupJobsPermission(@NonNull String packageName, int packageUid);
+
+ /**
* Report a snapshot of sync-related jobs back to the sync manager
*/
JobStorePersistStats getPersistStats();
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
index 7f5bb5c..57467e3 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -1840,7 +1840,9 @@
/* isFlexConstraintSatisfied */ false,
jobStatus.canApplyTransportAffinities(),
jobStatus.getNumAppliedFlexibleConstraints(),
- jobStatus.getNumDroppedFlexibleConstraints());
+ jobStatus.getNumDroppedFlexibleConstraints(),
+ jobStatus.getFilteredTraceTag(),
+ jobStatus.getFilteredDebugTags());
// If the job is immediately ready to run, then we can just immediately
// put it in the pending list and try to schedule it. This is especially
@@ -2288,7 +2290,9 @@
cancelled.isConstraintSatisfied(JobStatus.CONSTRAINT_FLEXIBLE),
cancelled.canApplyTransportAffinities(),
cancelled.getNumAppliedFlexibleConstraints(),
- cancelled.getNumDroppedFlexibleConstraints());
+ cancelled.getNumDroppedFlexibleConstraints(),
+ cancelled.getFilteredTraceTag(),
+ cancelled.getFilteredDebugTags());
}
// If this is a replacement, bring in the new version of the job
if (incomingJob != null) {
@@ -4193,6 +4197,11 @@
}
@Override
+ public boolean hasRunBackupJobsPermission(@NonNull String packageName, int packageUid) {
+ return JobSchedulerService.this.hasRunBackupJobsPermission(packageName, packageUid);
+ }
+
+ @Override
public JobStorePersistStats getPersistStats() {
synchronized (mLock) {
return new JobStorePersistStats(mJobs.getPersistStats());
@@ -4355,6 +4364,22 @@
}
/**
+ * Returns whether the app holds the {@link Manifest.permission.RUN_BACKUP_JOBS} permission.
+ */
+ private boolean hasRunBackupJobsPermission(@NonNull String packageName, int packageUid) {
+ if (packageName == null) {
+ Slog.wtfStack(TAG,
+ "Expected a non-null package name when calling hasRunBackupJobsPermission");
+ return false;
+ }
+
+ return PermissionChecker.checkPermissionForPreflight(getTestableContext(),
+ android.Manifest.permission.RUN_BACKUP_JOBS,
+ PermissionChecker.PID_UNKNOWN, packageUid, packageName)
+ == PermissionChecker.PERMISSION_GRANTED;
+ }
+
+ /**
* Binder stub trampoline implementation
*/
final class JobSchedulerStub extends IJobScheduler.Stub {
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
index fe55e27..8ab7d2f 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
@@ -541,7 +541,9 @@
job.isConstraintSatisfied(JobStatus.CONSTRAINT_FLEXIBLE),
job.canApplyTransportAffinities(),
job.getNumAppliedFlexibleConstraints(),
- job.getNumDroppedFlexibleConstraints());
+ job.getNumDroppedFlexibleConstraints(),
+ job.getFilteredTraceTag(),
+ job.getFilteredDebugTags());
sEnqueuedJwiAtJobStart.logSampleWithUid(job.getUid(), job.getWorkCount());
final String sourcePackage = job.getSourcePackageName();
if (Trace.isTagEnabled(Trace.TRACE_TAG_SYSTEM_SERVER)) {
@@ -1630,7 +1632,9 @@
completedJob.isConstraintSatisfied(JobStatus.CONSTRAINT_FLEXIBLE),
completedJob.canApplyTransportAffinities(),
completedJob.getNumAppliedFlexibleConstraints(),
- completedJob.getNumDroppedFlexibleConstraints());
+ completedJob.getNumDroppedFlexibleConstraints(),
+ completedJob.getFilteredTraceTag(),
+ completedJob.getFilteredDebugTags());
if (Trace.isTagEnabled(Trace.TRACE_TAG_SYSTEM_SERVER)) {
Trace.asyncTraceForTrackEnd(Trace.TRACE_TAG_SYSTEM_SERVER, "JobScheduler",
getId());
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
index d39863c..2ea980d 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
@@ -48,6 +48,7 @@
import android.util.ArraySet;
import android.util.IndentingPrintWriter;
import android.util.Pair;
+import android.util.Patterns;
import android.util.Range;
import android.util.Slog;
import android.util.TimeUtils;
@@ -76,6 +77,7 @@
import java.util.Objects;
import java.util.Random;
import java.util.function.Predicate;
+import java.util.regex.Pattern;
/**
* Uniquely identifies a job internally.
@@ -203,6 +205,17 @@
// TODO(b/129954980): ensure this doesn't spam statsd, especially at boot
private static final boolean STATS_LOG_ENABLED = false;
+ /**
+ * Simple patterns to match some common forms of PII. This is not intended all-encompassing and
+ * any clients should aim to do additional filtering.
+ */
+ private static final ArrayMap<Pattern, String> BASIC_PII_FILTERS = new ArrayMap<>();
+
+ static {
+ BASIC_PII_FILTERS.put(Patterns.EMAIL_ADDRESS, "[EMAIL]");
+ BASIC_PII_FILTERS.put(Patterns.PHONE, "[PHONE]");
+ }
+
// No override.
public static final int OVERRIDE_NONE = 0;
// Override to improve sorting order. Does not affect constraint evaluation.
@@ -250,6 +263,18 @@
private final long mLoggingJobId;
/**
+ * List of tags from {@link JobInfo#getDebugTags()}, filtered using {@link #BASIC_PII_FILTERS}.
+ * Lazily loaded in {@link #getFilteredDebugTags()}.
+ */
+ @Nullable
+ private String[] mFilteredDebugTags;
+ /**
+ * Trace tag from {@link JobInfo#getTraceTag()}, filtered using {@link #BASIC_PII_FILTERS}.
+ * Lazily loaded in {@link #getFilteredTraceTag()}.
+ */
+ @Nullable
+ private String mFilteredTraceTag;
+ /**
* Tag to identify the wakelock held for this job. Lazily loaded in
* {@link #getWakelockTag()} since it's not typically needed until the job is about to run.
*/
@@ -1197,21 +1222,25 @@
return ACTIVE_INDEX;
}
- final int bucketWithMediaExemption;
- if (actualBucket != RESTRICTED_INDEX && actualBucket != NEVER_INDEX
- && mHasMediaBackupExemption) {
+ final boolean isEligibleAsBackupJob = job.getTriggerContentUris() != null
+ && job.getRequiredNetwork() != null
+ && !job.hasLateConstraint()
+ && mJobSchedulerInternal.hasRunBackupJobsPermission(sourcePackageName, sourceUid);
+ final boolean isBackupExempt = mHasMediaBackupExemption || isEligibleAsBackupJob;
+ final int bucketWithBackupExemption;
+ if (actualBucket != RESTRICTED_INDEX && actualBucket != NEVER_INDEX && isBackupExempt) {
// Treat it as if it's at most WORKING_INDEX (lower index grants higher quota) since
// media backup jobs are important to the user, and the source package may not have
// been used directly in a while.
- bucketWithMediaExemption = Math.min(WORKING_INDEX, actualBucket);
+ bucketWithBackupExemption = Math.min(WORKING_INDEX, actualBucket);
} else {
- bucketWithMediaExemption = actualBucket;
+ bucketWithBackupExemption = actualBucket;
}
// If the app is considered buggy, but hasn't yet been put in the RESTRICTED bucket
// (potentially because it's used frequently by the user), limit its effective bucket
// so that it doesn't get to run as much as a normal ACTIVE app.
- if (isBuggy && bucketWithMediaExemption < WORKING_INDEX) {
+ if (isBuggy && bucketWithBackupExemption < WORKING_INDEX) {
if (!mIsDowngradedDueToBuggyApp) {
// Safety check to avoid logging multiple times for the same job.
Counter.logIncrementWithUid(
@@ -1221,7 +1250,7 @@
}
return WORKING_INDEX;
}
- return bucketWithMediaExemption;
+ return bucketWithBackupExemption;
}
/** Returns the real standby bucket of the job. */
@@ -1325,6 +1354,47 @@
return batteryName;
}
+ @VisibleForTesting
+ @NonNull
+ static String applyBasicPiiFilters(@NonNull String val) {
+ for (int i = BASIC_PII_FILTERS.size() - 1; i >= 0; --i) {
+ val = BASIC_PII_FILTERS.keyAt(i).matcher(val).replaceAll(BASIC_PII_FILTERS.valueAt(i));
+ }
+ return val;
+ }
+
+ /**
+ * List of tags from {@link JobInfo#getDebugTags()}, filtered using a basic set of PII filters.
+ */
+ @NonNull
+ public String[] getFilteredDebugTags() {
+ if (mFilteredDebugTags != null) {
+ return mFilteredDebugTags;
+ }
+ final ArraySet<String> debugTags = job.getDebugTagsArraySet();
+ mFilteredDebugTags = new String[debugTags.size()];
+ for (int i = 0; i < mFilteredDebugTags.length; ++i) {
+ mFilteredDebugTags[i] = applyBasicPiiFilters(debugTags.valueAt(i));
+ }
+ return mFilteredDebugTags;
+ }
+
+ /**
+ * Trace tag from {@link JobInfo#getTraceTag()}, filtered using a basic set of PII filters.
+ */
+ @Nullable
+ public String getFilteredTraceTag() {
+ if (mFilteredTraceTag != null) {
+ return mFilteredTraceTag;
+ }
+ final String rawTag = job.getTraceTag();
+ if (rawTag == null) {
+ return null;
+ }
+ mFilteredTraceTag = applyBasicPiiFilters(rawTag);
+ return mFilteredTraceTag;
+ }
+
/** Return the String to be used as the tag for the wakelock held for this job. */
@NonNull
public String getWakelockTag() {
diff --git a/core/TEST_MAPPING b/core/TEST_MAPPING
index fd571c9..24ba5c4 100644
--- a/core/TEST_MAPPING
+++ b/core/TEST_MAPPING
@@ -20,5 +20,15 @@
"core/tests/coretests/src/com/android/internal/inputmethod/.*"
]
}
- ]
+ ],
+ "postsubmit": [
+ {
+ "name": "ContactKeysManagerTest",
+ "options": [
+ {
+ "include-filter": "android.provider.cts.contactkeys."
+ }
+ ]
+ }
+ ]
}
diff --git a/core/api/current.txt b/core/api/current.txt
index 9e3919d..55ea2f4 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -147,6 +147,7 @@
field public static final String MANAGE_DEVICE_POLICY_CAMERA = "android.permission.MANAGE_DEVICE_POLICY_CAMERA";
field public static final String MANAGE_DEVICE_POLICY_CERTIFICATES = "android.permission.MANAGE_DEVICE_POLICY_CERTIFICATES";
field public static final String MANAGE_DEVICE_POLICY_COMMON_CRITERIA_MODE = "android.permission.MANAGE_DEVICE_POLICY_COMMON_CRITERIA_MODE";
+ field @FlaggedApi("android.view.contentprotection.flags.manage_device_policy_enabled") public static final String MANAGE_DEVICE_POLICY_CONTENT_PROTECTION = "android.permission.MANAGE_DEVICE_POLICY_CONTENT_PROTECTION";
field public static final String MANAGE_DEVICE_POLICY_DEBUGGING_FEATURES = "android.permission.MANAGE_DEVICE_POLICY_DEBUGGING_FEATURES";
field public static final String MANAGE_DEVICE_POLICY_DEFAULT_SMS = "android.permission.MANAGE_DEVICE_POLICY_DEFAULT_SMS";
field public static final String MANAGE_DEVICE_POLICY_DEVICE_IDENTIFIERS = "android.permission.MANAGE_DEVICE_POLICY_DEVICE_IDENTIFIERS";
@@ -444,6 +445,7 @@
field public static final int alertDialogTheme = 16843529; // 0x1010309
field public static final int alignmentMode = 16843642; // 0x101037a
field public static final int allContactsName = 16843468; // 0x10102cc
+ field @FlaggedApi("android.content.pm.relative_reference_intent_filters") public static final int allow;
field public static final int allowAudioPlaybackCapture = 16844289; // 0x1010601
field public static final int allowBackup = 16843392; // 0x1010280
field public static final int allowClearUserData = 16842757; // 0x1010005
@@ -847,6 +849,7 @@
field public static final int format24Hour = 16843723; // 0x10103cb
field public static final int fraction = 16843992; // 0x10104d8
field public static final int fragment = 16843491; // 0x10102e3
+ field @FlaggedApi("android.content.pm.relative_reference_intent_filters") public static final int fragmentAdvancedPattern;
field public static final int fragmentAllowEnterTransitionOverlap = 16843976; // 0x10104c8
field public static final int fragmentAllowReturnTransitionOverlap = 16843977; // 0x10104c9
field public static final int fragmentCloseEnterAnimation = 16843495; // 0x10102e7
@@ -857,10 +860,13 @@
field public static final int fragmentFadeExitAnimation = 16843498; // 0x10102ea
field public static final int fragmentOpenEnterAnimation = 16843493; // 0x10102e5
field public static final int fragmentOpenExitAnimation = 16843494; // 0x10102e6
+ field @FlaggedApi("android.content.pm.relative_reference_intent_filters") public static final int fragmentPattern;
+ field @FlaggedApi("android.content.pm.relative_reference_intent_filters") public static final int fragmentPrefix;
field public static final int fragmentReenterTransition = 16843975; // 0x10104c7
field public static final int fragmentReturnTransition = 16843973; // 0x10104c5
field public static final int fragmentSharedElementEnterTransition = 16843972; // 0x10104c4
field public static final int fragmentSharedElementReturnTransition = 16843974; // 0x10104c6
+ field @FlaggedApi("android.content.pm.relative_reference_intent_filters") public static final int fragmentSuffix;
field public static final int freezesText = 16843116; // 0x101016c
field public static final int fromAlpha = 16843210; // 0x10101ca
field public static final int fromDegrees = 16843187; // 0x10101b3
@@ -1329,10 +1335,15 @@
field public static final int propertyYName = 16843893; // 0x1010475
field public static final int protectionLevel = 16842761; // 0x1010009
field public static final int publicKey = 16843686; // 0x10103a6
+ field @FlaggedApi("android.content.pm.relative_reference_intent_filters") public static final int query;
field public static final int queryActionMsg = 16843227; // 0x10101db
+ field @FlaggedApi("android.content.pm.relative_reference_intent_filters") public static final int queryAdvancedPattern;
field public static final int queryAfterZeroResults = 16843394; // 0x1010282
field public static final int queryBackground = 16843911; // 0x1010487
field public static final int queryHint = 16843608; // 0x1010358
+ field @FlaggedApi("android.content.pm.relative_reference_intent_filters") public static final int queryPattern;
+ field @FlaggedApi("android.content.pm.relative_reference_intent_filters") public static final int queryPrefix;
+ field @FlaggedApi("android.content.pm.relative_reference_intent_filters") public static final int querySuffix;
field public static final int quickContactBadgeStyleSmallWindowLarge = 16843443; // 0x10102b3
field public static final int quickContactBadgeStyleSmallWindowMedium = 16843442; // 0x10102b2
field public static final int quickContactBadgeStyleSmallWindowSmall = 16843441; // 0x10102b1
@@ -8184,6 +8195,9 @@
field public static final String ACTION_SET_NEW_PASSWORD = "android.app.action.SET_NEW_PASSWORD";
field public static final String ACTION_START_ENCRYPTION = "android.app.action.START_ENCRYPTION";
field public static final String ACTION_SYSTEM_UPDATE_POLICY_CHANGED = "android.app.action.SYSTEM_UPDATE_POLICY_CHANGED";
+ field @FlaggedApi("android.view.contentprotection.flags.manage_device_policy_enabled") public static final int CONTENT_PROTECTION_DISABLED = 1; // 0x1
+ field @FlaggedApi("android.view.contentprotection.flags.manage_device_policy_enabled") public static final int CONTENT_PROTECTION_ENABLED = 2; // 0x2
+ field @FlaggedApi("android.view.contentprotection.flags.manage_device_policy_enabled") public static final int CONTENT_PROTECTION_NOT_CONTROLLED_BY_POLICY = 0; // 0x0
field public static final String DELEGATION_APP_RESTRICTIONS = "delegation-app-restrictions";
field public static final String DELEGATION_BLOCK_UNINSTALL = "delegation-block-uninstall";
field public static final String DELEGATION_CERT_INSTALL = "delegation-cert-install";
@@ -10594,6 +10608,7 @@
field public static final String CONNECTIVITY_DIAGNOSTICS_SERVICE = "connectivity_diagnostics";
field public static final String CONNECTIVITY_SERVICE = "connectivity";
field public static final String CONSUMER_IR_SERVICE = "consumer_ir";
+ field @FlaggedApi("android.provider.user_keys") public static final String CONTACT_KEYS_SERVICE = "contact_keys";
field public static final int CONTEXT_IGNORE_SECURITY = 2; // 0x2
field public static final int CONTEXT_INCLUDE_CODE = 1; // 0x1
field public static final int CONTEXT_RESTRICTED = 4; // 0x4
@@ -11387,10 +11402,12 @@
method public final void addDataScheme(String);
method public final void addDataSchemeSpecificPart(String, int);
method public final void addDataType(String) throws android.content.IntentFilter.MalformedMimeTypeException;
+ method @FlaggedApi("android.content.pm.relative_reference_intent_filters") public final void addUriRelativeFilterGroup(@NonNull android.content.UriRelativeFilterGroup);
method @NonNull public java.util.function.Predicate<android.content.Intent> asPredicate();
method @NonNull public java.util.function.Predicate<android.content.Intent> asPredicateWithTypeResolution(@NonNull android.content.ContentResolver);
method public final java.util.Iterator<android.content.IntentFilter.AuthorityEntry> authoritiesIterator();
method public final java.util.Iterator<java.lang.String> categoriesIterator();
+ method @FlaggedApi("android.content.pm.relative_reference_intent_filters") public final void clearUriRelativeFilterGroups();
method public final int countActions();
method public final int countCategories();
method public final int countDataAuthorities();
@@ -11398,6 +11415,7 @@
method public final int countDataSchemeSpecificParts();
method public final int countDataSchemes();
method public final int countDataTypes();
+ method @FlaggedApi("android.content.pm.relative_reference_intent_filters") public final int countUriRelativeFilterGroups();
method public static android.content.IntentFilter create(String, String);
method public final int describeContents();
method public void dump(android.util.Printer, String);
@@ -11409,6 +11427,7 @@
method public final android.os.PatternMatcher getDataSchemeSpecificPart(int);
method public final String getDataType(int);
method public final int getPriority();
+ method @FlaggedApi("android.content.pm.relative_reference_intent_filters") @NonNull public final android.content.UriRelativeFilterGroup getUriRelativeFilterGroup(int);
method public final boolean hasAction(String);
method public final boolean hasCategory(String);
method public final boolean hasDataAuthority(android.net.Uri);
@@ -11830,6 +11849,27 @@
field public static final long INVALID_TIME = -9223372036854775808L; // 0x8000000000000000L
}
+ @FlaggedApi("android.content.pm.relative_reference_intent_filters") public final class UriRelativeFilter {
+ ctor public UriRelativeFilter(int, int, @NonNull String);
+ method @NonNull public String getFilter();
+ method public int getPatternType();
+ method public int getUriPart();
+ method public boolean matchData(@NonNull android.net.Uri);
+ field public static final int FRAGMENT = 2; // 0x2
+ field public static final int PATH = 0; // 0x0
+ field public static final int QUERY = 1; // 0x1
+ }
+
+ @FlaggedApi("android.content.pm.relative_reference_intent_filters") public final class UriRelativeFilterGroup {
+ ctor public UriRelativeFilterGroup(int);
+ method public void addUriRelativeFilter(@NonNull android.content.UriRelativeFilter);
+ method public int getAction();
+ method @NonNull public java.util.Collection<android.content.UriRelativeFilter> getUriRelativeFilters();
+ method public boolean matchData(@NonNull android.net.Uri);
+ field public static final int ACTION_ALLOW = 0; // 0x0
+ field public static final int ACTION_BLOCK = 1; // 0x1
+ }
+
}
package android.content.om {
@@ -22335,6 +22375,7 @@
method @NonNull public java.util.List<java.lang.String> getSupportedVendorParameters();
method @Nullable public static android.media.Image mapHardwareBuffer(@NonNull android.hardware.HardwareBuffer);
method public void queueInputBuffer(int, int, int, long, int) throws android.media.MediaCodec.CryptoException;
+ method @FlaggedApi("com.android.media.codec.flags.large_audio_frame") public void queueInputBuffers(int, @NonNull java.util.ArrayDeque<android.media.MediaCodec.BufferInfo>);
method public void queueSecureInputBuffer(int, int, @NonNull android.media.MediaCodec.CryptoInfo, long, int) throws android.media.MediaCodec.CryptoException;
method public void release();
method public void releaseOutputBuffer(int, boolean);
@@ -22396,6 +22437,7 @@
method public abstract void onError(@NonNull android.media.MediaCodec, @NonNull android.media.MediaCodec.CodecException);
method public abstract void onInputBufferAvailable(@NonNull android.media.MediaCodec, int);
method public abstract void onOutputBufferAvailable(@NonNull android.media.MediaCodec, int, @NonNull android.media.MediaCodec.BufferInfo);
+ method @FlaggedApi("com.android.media.codec.flags.large_audio_frame") public void onOutputBuffersAvailable(@NonNull android.media.MediaCodec, int, @NonNull java.util.ArrayDeque<android.media.MediaCodec.BufferInfo>);
method public abstract void onOutputFormatChanged(@NonNull android.media.MediaCodec, @NonNull android.media.MediaFormat);
}
@@ -22483,6 +22525,7 @@
}
public static final class MediaCodec.OutputFrame {
+ method @FlaggedApi("com.android.media.codec.flags.large_audio_frame") @NonNull public java.util.ArrayDeque<android.media.MediaCodec.BufferInfo> getBufferInfos();
method @NonNull public java.util.Set<java.lang.String> getChangedKeys();
method public int getFlags();
method @NonNull public android.media.MediaFormat getFormat();
@@ -22498,6 +22541,7 @@
public final class MediaCodec.QueueRequest {
method public void queue();
+ method @FlaggedApi("com.android.media.codec.flags.large_audio_frame") @NonNull public android.media.MediaCodec.QueueRequest setBufferInfos(@NonNull java.util.ArrayDeque<android.media.MediaCodec.BufferInfo>);
method @NonNull public android.media.MediaCodec.QueueRequest setByteBufferParameter(@NonNull String, @NonNull java.nio.ByteBuffer);
method @NonNull public android.media.MediaCodec.QueueRequest setEncryptedLinearBlock(@NonNull android.media.MediaCodec.LinearBlock, int, int, @NonNull android.media.MediaCodec.CryptoInfo);
method @NonNull public android.media.MediaCodec.QueueRequest setFlags(int);
@@ -33470,6 +33514,7 @@
field public static final String DISALLOW_SHARING_ADMIN_CONFIGURED_WIFI = "no_sharing_admin_configured_wifi";
field public static final String DISALLOW_SMS = "no_sms";
field public static final String DISALLOW_SYSTEM_ERROR_DIALOGS = "no_system_error_dialogs";
+ field @FlaggedApi("com.android.net.thread.flags.thread_user_restriction_enabled") public static final String DISALLOW_THREAD_NETWORK = "no_thread_network";
field public static final String DISALLOW_ULTRA_WIDEBAND_RADIO = "no_ultra_wideband_radio";
field public static final String DISALLOW_UNIFIED_PASSWORD = "no_unified_password";
field public static final String DISALLOW_UNINSTALL_APPS = "no_uninstall_apps";
@@ -35195,6 +35240,54 @@
field public static final String LONGITUDE = "longitude";
}
+ @FlaggedApi("android.provider.user_keys") public class ContactKeysManager {
+ method @NonNull @RequiresPermission(android.Manifest.permission.READ_CONTACTS) public java.util.List<android.provider.ContactKeysManager.ContactKey> getAllContactKeys(@NonNull String);
+ method @NonNull @RequiresPermission(android.Manifest.permission.READ_CONTACTS) public java.util.List<android.provider.ContactKeysManager.SelfKey> getAllSelfKeys();
+ method @Nullable @RequiresPermission(android.Manifest.permission.READ_CONTACTS) public android.provider.ContactKeysManager.ContactKey getContactKey(@NonNull String, @NonNull String, @NonNull String);
+ method public static int getMaxKeySizeBytes();
+ method @NonNull @RequiresPermission(android.Manifest.permission.READ_CONTACTS) public java.util.List<android.provider.ContactKeysManager.ContactKey> getOwnerContactKeys(@NonNull String);
+ method @NonNull @RequiresPermission(android.Manifest.permission.READ_CONTACTS) public java.util.List<android.provider.ContactKeysManager.SelfKey> getOwnerSelfKeys();
+ method @Nullable @RequiresPermission(android.Manifest.permission.READ_CONTACTS) public android.provider.ContactKeysManager.SelfKey getSelfKey(@NonNull String, @NonNull String);
+ method @RequiresPermission(android.Manifest.permission.WRITE_CONTACTS) public boolean removeContactKey(@NonNull String, @NonNull String, @NonNull String);
+ method @RequiresPermission(android.Manifest.permission.WRITE_CONTACTS) public boolean removeSelfKey(@NonNull String, @NonNull String);
+ method @RequiresPermission(android.Manifest.permission.WRITE_CONTACTS) public boolean updateContactKeyLocalVerificationState(@NonNull String, @NonNull String, @NonNull String, int);
+ method @RequiresPermission(android.Manifest.permission.WRITE_CONTACTS) public boolean updateContactKeyRemoteVerificationState(@NonNull String, @NonNull String, @NonNull String, int);
+ method @RequiresPermission(android.Manifest.permission.WRITE_CONTACTS) public void updateOrInsertContactKey(@NonNull String, @NonNull String, @NonNull String, @NonNull byte[]);
+ method @RequiresPermission(android.Manifest.permission.WRITE_CONTACTS) public boolean updateOrInsertSelfKey(@NonNull String, @NonNull String, @NonNull byte[]);
+ method @RequiresPermission(android.Manifest.permission.WRITE_CONTACTS) public boolean updateSelfKeyRemoteVerificationState(@NonNull String, @NonNull String, int);
+ field public static final int UNVERIFIED = 0; // 0x0
+ field public static final int VERIFICATION_FAILED = 1; // 0x1
+ field public static final int VERIFIED = 2; // 0x2
+ }
+
+ public static final class ContactKeysManager.ContactKey implements android.os.Parcelable {
+ method public int describeContents();
+ method @NonNull public String getAccountId();
+ method @Nullable public String getDeviceId();
+ method @Nullable public String getDisplayName();
+ method @Nullable public String getEmailAddress();
+ method @Nullable public byte[] getKeyValue();
+ method public int getLocalVerificationState();
+ method @NonNull public String getOwnerPackageName();
+ method @Nullable public String getPhoneNumber();
+ method public int getRemoteVerificationState();
+ method public long getTimeUpdated();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.provider.ContactKeysManager.ContactKey> CREATOR;
+ }
+
+ public static final class ContactKeysManager.SelfKey implements android.os.Parcelable {
+ method public int describeContents();
+ method @NonNull public String getAccountId();
+ method @Nullable public String getDeviceId();
+ method @Nullable public byte[] getKeyValue();
+ method @NonNull public String getOwnerPackageName();
+ method public int getRemoteVerificationState();
+ method public long getTimeUpdated();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.provider.ContactKeysManager.SelfKey> CREATOR;
+ }
+
@Deprecated public class Contacts {
field @Deprecated public static final String AUTHORITY = "contacts";
field @Deprecated public static final android.net.Uri CONTENT_URI;
@@ -53666,13 +53759,13 @@
method @Deprecated public android.view.Display getDefaultDisplay();
method @NonNull public default android.view.WindowMetrics getMaximumWindowMetrics();
method public default boolean isCrossWindowBlurEnabled();
- method @FlaggedApi("com.android.window.flags.surface_control_input_receiver") @NonNull public default android.os.IBinder registerBatchedSurfaceControlInputReceiver(int, @NonNull android.os.IBinder, @NonNull android.view.SurfaceControl, @NonNull android.view.Choreographer, @NonNull android.view.SurfaceControlInputReceiver);
+ method @FlaggedApi("com.android.window.flags.surface_control_input_receiver") public default void registerBatchedSurfaceControlInputReceiver(int, @NonNull android.os.IBinder, @NonNull android.view.SurfaceControl, @NonNull android.view.Choreographer, @NonNull android.view.SurfaceControlInputReceiver);
method @FlaggedApi("com.android.window.flags.trusted_presentation_listener_for_window") public default void registerTrustedPresentationListener(@NonNull android.os.IBinder, @NonNull android.window.TrustedPresentationThresholds, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
- method @FlaggedApi("com.android.window.flags.surface_control_input_receiver") @NonNull public default android.os.IBinder registerUnbatchedSurfaceControlInputReceiver(int, @NonNull android.os.IBinder, @NonNull android.view.SurfaceControl, @NonNull android.os.Looper, @NonNull android.view.SurfaceControlInputReceiver);
+ method @FlaggedApi("com.android.window.flags.surface_control_input_receiver") public default void registerUnbatchedSurfaceControlInputReceiver(int, @NonNull android.os.IBinder, @NonNull android.view.SurfaceControl, @NonNull android.os.Looper, @NonNull android.view.SurfaceControlInputReceiver);
method public default void removeCrossWindowBlurEnabledListener(@NonNull java.util.function.Consumer<java.lang.Boolean>);
method public default void removeProposedRotationListener(@NonNull java.util.function.IntConsumer);
method public void removeViewImmediate(android.view.View);
- method @FlaggedApi("com.android.window.flags.surface_control_input_receiver") public default void unregisterSurfaceControlInputReceiver(@NonNull android.os.IBinder);
+ method @FlaggedApi("com.android.window.flags.surface_control_input_receiver") public default void unregisterSurfaceControlInputReceiver(@NonNull android.view.SurfaceControl);
method @FlaggedApi("com.android.window.flags.trusted_presentation_listener_for_window") public default void unregisterTrustedPresentationListener(@NonNull java.util.function.Consumer<java.lang.Boolean>);
field public static final String PROPERTY_ACTIVITY_EMBEDDING_ALLOW_SYSTEM_OVERRIDE = "android.window.PROPERTY_ACTIVITY_EMBEDDING_ALLOW_SYSTEM_OVERRIDE";
field public static final String PROPERTY_ACTIVITY_EMBEDDING_SPLITS_ENABLED = "android.window.PROPERTY_ACTIVITY_EMBEDDING_SPLITS_ENABLED";
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 6a1df16..2c1f2fd 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -129,6 +129,8 @@
field public static final String DISABLE_SYSTEM_SOUND_EFFECTS = "android.permission.DISABLE_SYSTEM_SOUND_EFFECTS";
field public static final String DISPATCH_PROVISIONING_MESSAGE = "android.permission.DISPATCH_PROVISIONING_MESSAGE";
field public static final String DOMAIN_VERIFICATION_AGENT = "android.permission.DOMAIN_VERIFICATION_AGENT";
+ field @FlaggedApi("com.android.window.flags.untrusted_embedding_any_app_permission") public static final String EMBED_ANY_APP_IN_UNTRUSTED_MODE = "android.permission.EMBED_ANY_APP_IN_UNTRUSTED_MODE";
+ field @FlaggedApi("android.content.pm.emergency_install_permission") public static final String EMERGENCY_INSTALL_PACKAGES = "android.permission.EMERGENCY_INSTALL_PACKAGES";
field public static final String ENTER_CAR_MODE_PRIORITIZED = "android.permission.ENTER_CAR_MODE_PRIORITIZED";
field public static final String EXEMPT_FROM_AUDIO_RECORD_RESTRICTIONS = "android.permission.EXEMPT_FROM_AUDIO_RECORD_RESTRICTIONS";
field public static final String FORCE_BACK = "android.permission.FORCE_BACK";
@@ -4231,6 +4233,7 @@
public final class UserProperties implements android.os.Parcelable {
method public int describeContents();
method public int getCrossProfileContentSharingStrategy();
+ method @FlaggedApi("android.multiuser.support_hiding_profiles") @NonNull public int getProfileApiVisibility();
method public int getShowInQuietMode();
method public int getShowInSharingSurfaces();
method public boolean isCredentialShareableWithParent();
@@ -4240,6 +4243,9 @@
field public static final int CROSS_PROFILE_CONTENT_SHARING_DELEGATE_FROM_PARENT = 1; // 0x1
field public static final int CROSS_PROFILE_CONTENT_SHARING_NO_DELEGATION = 0; // 0x0
field public static final int CROSS_PROFILE_CONTENT_SHARING_UNKNOWN = -1; // 0xffffffff
+ field @FlaggedApi("android.multiuser.support_hiding_profiles") public static final int PROFILE_API_VISIBILITY_HIDDEN = 1; // 0x1
+ field @FlaggedApi("android.multiuser.support_hiding_profiles") public static final int PROFILE_API_VISIBILITY_UNKNOWN = -1; // 0xffffffff
+ field @FlaggedApi("android.multiuser.support_hiding_profiles") public static final int PROFILE_API_VISIBILITY_VISIBLE = 0; // 0x0
field public static final int SHOW_IN_QUIET_MODE_DEFAULT = 2; // 0x2
field public static final int SHOW_IN_QUIET_MODE_HIDDEN = 1; // 0x1
field public static final int SHOW_IN_QUIET_MODE_PAUSED = 0; // 0x0
@@ -4375,6 +4381,41 @@
}
+package android.credentials.selection {
+
+ @FlaggedApi("android.credentials.flags.configurable_selector_ui_enabled") public final class FailureResult {
+ ctor public FailureResult(int, @Nullable String);
+ method public int getErrorCode();
+ method @Nullable public String getErrorMessage();
+ field public static final int ERROR_CODE_CANCELED_AND_LAUNCHED_SETTINGS = 2; // 0x2
+ field public static final int ERROR_CODE_DIALOG_CANCELED_BY_USER = 1; // 0x1
+ field public static final int ERROR_CODE_UI_FAILURE = 0; // 0x0
+ }
+
+ @FlaggedApi("android.credentials.flags.configurable_selector_ui_enabled") public final class ProviderPendingIntentResponse implements android.os.Parcelable {
+ ctor public ProviderPendingIntentResponse(int, @Nullable android.content.Intent);
+ method public int describeContents();
+ method public int getResultCode();
+ method @Nullable public android.content.Intent getResultData();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.credentials.selection.ProviderPendingIntentResponse> CREATOR;
+ }
+
+ @FlaggedApi("android.credentials.flags.configurable_selector_ui_enabled") public final class ResultHelper {
+ method public static void sendFailureResult(@NonNull android.os.ResultReceiver, @NonNull android.credentials.selection.FailureResult);
+ method public static void sendUserSelectionResult(@NonNull android.os.ResultReceiver, @NonNull android.credentials.selection.UserSelectionResult);
+ }
+
+ @FlaggedApi("android.credentials.flags.configurable_selector_ui_enabled") public final class UserSelectionResult {
+ ctor public UserSelectionResult(@NonNull String, @NonNull String, @NonNull String, @Nullable android.credentials.selection.ProviderPendingIntentResponse);
+ method @NonNull public String getEntryKey();
+ method @NonNull public String getEntrySubkey();
+ method @Nullable public android.credentials.selection.ProviderPendingIntentResponse getPendingIntentProviderResponse();
+ method @NonNull public String getProviderId();
+ }
+
+}
+
package android.database {
public abstract class ContentObserver {
@@ -17173,38 +17214,38 @@
}
@FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public final class SatelliteManager {
- method @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void addSatelliteAttachRestrictionForCarrier(int, int, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
- method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void deprovisionSatelliteService(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
- method @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") @NonNull @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public java.util.List<java.lang.String> getAllSatellitePlmnsForCarrier(int);
- method @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") @NonNull @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public java.util.Set<java.lang.Integer> getSatelliteAttachRestrictionReasonsForCarrier(int);
- method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void pollPendingSatelliteDatagrams(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
- method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void provisionSatelliteService(@NonNull String, @NonNull byte[], @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
+ method @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void addAttachRestrictionForCarrier(int, int, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
+ method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void deprovisionService(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
+ method @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") @NonNull @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public java.util.Set<java.lang.Integer> getAttachRestrictionReasonsForCarrier(int);
+ method @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") @NonNull @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public java.util.List<java.lang.String> getSatellitePlmnsForCarrier(int);
+ method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void pollPendingDatagrams(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
+ method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void provisionService(@NonNull String, @NonNull byte[], @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
+ method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public int registerForCapabilitiesChanged(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.satellite.SatelliteCapabilitiesCallback);
+ method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public int registerForIncomingDatagram(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.satellite.SatelliteDatagramCallback);
+ method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public int registerForModemStateChanged(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.satellite.SatelliteModemStateCallback);
method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void registerForNtnSignalStrengthChanged(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.satellite.NtnSignalStrengthCallback);
- method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public int registerForSatelliteCapabilitiesChanged(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.satellite.SatelliteCapabilitiesCallback);
- method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public int registerForSatelliteDatagram(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.satellite.SatelliteDatagramCallback);
- method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public int registerForSatelliteModemStateChanged(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.satellite.SatelliteModemStateCallback);
- method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public int registerForSatelliteProvisionStateChanged(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.satellite.SatelliteProvisionStateCallback);
- method @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void removeSatelliteAttachRestrictionForCarrier(int, int, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
+ method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public int registerForProvisionStateChanged(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.satellite.SatelliteProvisionStateCallback);
+ method @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void removeAttachRestrictionForCarrier(int, int, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
+ method @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void requestAttachEnabledForCarrier(int, boolean, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
+ method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void requestCapabilities(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<android.telephony.satellite.SatelliteCapabilities,android.telephony.satellite.SatelliteManager.SatelliteException>);
+ method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void requestEnabled(boolean, boolean, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
+ method @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void requestIsAttachEnabledForCarrier(int, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Boolean,android.telephony.satellite.SatelliteManager.SatelliteException>);
+ method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void requestIsCommunicationAllowedForCurrentLocation(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Boolean,android.telephony.satellite.SatelliteManager.SatelliteException>);
method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void requestIsDemoModeEnabled(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Boolean,android.telephony.satellite.SatelliteManager.SatelliteException>);
- method @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void requestIsSatelliteAttachEnabledForCarrier(int, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Boolean,android.telephony.satellite.SatelliteManager.SatelliteException>);
- method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void requestIsSatelliteCommunicationAllowedForCurrentLocation(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Boolean,android.telephony.satellite.SatelliteManager.SatelliteException>);
- method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void requestIsSatelliteEnabled(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Boolean,android.telephony.satellite.SatelliteManager.SatelliteException>);
- method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void requestIsSatelliteProvisioned(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Boolean,android.telephony.satellite.SatelliteManager.SatelliteException>);
- method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public void requestIsSatelliteSupported(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Boolean,android.telephony.satellite.SatelliteManager.SatelliteException>);
+ method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void requestIsEnabled(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Boolean,android.telephony.satellite.SatelliteManager.SatelliteException>);
+ method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void requestIsProvisioned(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Boolean,android.telephony.satellite.SatelliteManager.SatelliteException>);
+ method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public void requestIsSupported(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Boolean,android.telephony.satellite.SatelliteManager.SatelliteException>);
method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void requestNtnSignalStrength(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<android.telephony.satellite.NtnSignalStrength,android.telephony.satellite.SatelliteManager.SatelliteException>);
- method @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void requestSatelliteAttachEnabledForCarrier(int, boolean, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
- method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void requestSatelliteCapabilities(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<android.telephony.satellite.SatelliteCapabilities,android.telephony.satellite.SatelliteManager.SatelliteException>);
- method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void requestSatelliteEnabled(boolean, boolean, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void requestTimeForNextSatelliteVisibility(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.time.Duration,android.telephony.satellite.SatelliteManager.SatelliteException>);
- method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void sendSatelliteDatagram(int, @NonNull android.telephony.satellite.SatelliteDatagram, boolean, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
+ method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void sendDatagram(int, @NonNull android.telephony.satellite.SatelliteDatagram, boolean, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void setDeviceAlignedWithSatellite(boolean);
- method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void startSatelliteTransmissionUpdates(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>, @NonNull android.telephony.satellite.SatelliteTransmissionUpdateCallback);
- method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void stopSatelliteTransmissionUpdates(@NonNull android.telephony.satellite.SatelliteTransmissionUpdateCallback, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
+ method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void startTransmissionUpdates(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>, @NonNull android.telephony.satellite.SatelliteTransmissionUpdateCallback);
+ method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void stopTransmissionUpdates(@NonNull android.telephony.satellite.SatelliteTransmissionUpdateCallback, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
+ method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void unregisterForCapabilitiesChanged(@NonNull android.telephony.satellite.SatelliteCapabilitiesCallback);
+ method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void unregisterForIncomingDatagram(@NonNull android.telephony.satellite.SatelliteDatagramCallback);
+ method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void unregisterForModemStateChanged(@NonNull android.telephony.satellite.SatelliteModemStateCallback);
method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void unregisterForNtnSignalStrengthChanged(@NonNull android.telephony.satellite.NtnSignalStrengthCallback);
- method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void unregisterForSatelliteCapabilitiesChanged(@NonNull android.telephony.satellite.SatelliteCapabilitiesCallback);
- method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void unregisterForSatelliteDatagram(@NonNull android.telephony.satellite.SatelliteDatagramCallback);
- method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void unregisterForSatelliteModemStateChanged(@NonNull android.telephony.satellite.SatelliteModemStateCallback);
- method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void unregisterForSatelliteProvisionStateChanged(@NonNull android.telephony.satellite.SatelliteProvisionStateCallback);
+ method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void unregisterForProvisionStateChanged(@NonNull android.telephony.satellite.SatelliteProvisionStateCallback);
field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int DATAGRAM_TYPE_LOCATION_SHARING = 2; // 0x2
field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int DATAGRAM_TYPE_SOS_MESSAGE = 1; // 0x1
field @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") public static final int DATAGRAM_TYPE_UNKNOWN = 0; // 0x0
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index b8b98a3..1fa2b5c 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -195,8 +195,11 @@
method public void setTaskOverlay(boolean, boolean);
}
- public static final class ActivityOptions.LaunchCookie {
+ public static final class ActivityOptions.LaunchCookie implements android.os.Parcelable {
ctor public ActivityOptions.LaunchCookie();
+ method public int describeContents();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.app.ActivityOptions.LaunchCookie> CREATOR;
}
public static interface ActivityOptions.OnAnimationFinishedListener {
@@ -1262,9 +1265,9 @@
}
-package android.credentials.ui {
+package android.credentials.selection {
- public final class AuthenticationEntry implements android.os.Parcelable {
+ @FlaggedApi("android.credentials.flags.configurable_selector_ui_enabled") public final class AuthenticationEntry implements android.os.Parcelable {
ctor public AuthenticationEntry(@NonNull String, @NonNull String, @NonNull android.app.slice.Slice, int);
ctor public AuthenticationEntry(@NonNull String, @NonNull String, @NonNull android.app.slice.Slice, int, @NonNull android.content.Intent);
method public int describeContents();
@@ -1274,32 +1277,47 @@
method @NonNull public int getStatus();
method @NonNull public String getSubkey();
method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.credentials.ui.AuthenticationEntry> CREATOR;
+ field @NonNull public static final android.os.Parcelable.Creator<android.credentials.selection.AuthenticationEntry> CREATOR;
field public static final int STATUS_LOCKED = 0; // 0x0
field public static final int STATUS_UNLOCKED_BUT_EMPTY_LESS_RECENT = 1; // 0x1
field public static final int STATUS_UNLOCKED_BUT_EMPTY_MOST_RECENT = 2; // 0x2
}
- public final class CreateCredentialProviderData extends android.credentials.ui.ProviderData implements android.os.Parcelable {
- ctor public CreateCredentialProviderData(@NonNull String, @NonNull java.util.List<android.credentials.ui.Entry>, @Nullable android.credentials.ui.Entry);
- method @Nullable public android.credentials.ui.Entry getRemoteEntry();
- method @NonNull public java.util.List<android.credentials.ui.Entry> getSaveEntries();
- field @NonNull public static final android.os.Parcelable.Creator<android.credentials.ui.CreateCredentialProviderData> CREATOR;
+ @FlaggedApi("android.credentials.flags.configurable_selector_ui_enabled") public class BaseDialogResult implements android.os.Parcelable {
+ ctor public BaseDialogResult(@Nullable android.os.IBinder);
+ ctor protected BaseDialogResult(@NonNull android.os.Parcel);
+ method public static void addToBundle(@NonNull android.credentials.selection.BaseDialogResult, @NonNull android.os.Bundle);
+ method public int describeContents();
+ method @Nullable public static android.credentials.selection.BaseDialogResult fromResultData(@NonNull android.os.Bundle);
+ method @Deprecated @Nullable public android.os.IBinder getRequestToken();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.credentials.selection.BaseDialogResult> CREATOR;
+ field public static final int RESULT_CODE_CANCELED_AND_LAUNCHED_SETTINGS = 1; // 0x1
+ field public static final int RESULT_CODE_DATA_PARSING_FAILURE = 3; // 0x3
+ field public static final int RESULT_CODE_DIALOG_COMPLETE_WITH_SELECTION = 2; // 0x2
+ field public static final int RESULT_CODE_DIALOG_USER_CANCELED = 0; // 0x0
}
- public static final class CreateCredentialProviderData.Builder {
+ @FlaggedApi("android.credentials.flags.configurable_selector_ui_enabled") public final class CreateCredentialProviderData extends android.credentials.selection.ProviderData implements android.os.Parcelable {
+ ctor public CreateCredentialProviderData(@NonNull String, @NonNull java.util.List<android.credentials.selection.Entry>, @Nullable android.credentials.selection.Entry);
+ method @Nullable public android.credentials.selection.Entry getRemoteEntry();
+ method @NonNull public java.util.List<android.credentials.selection.Entry> getSaveEntries();
+ field @NonNull public static final android.os.Parcelable.Creator<android.credentials.selection.CreateCredentialProviderData> CREATOR;
+ }
+
+ @FlaggedApi("android.credentials.flags.configurable_selector_ui_enabled") public static final class CreateCredentialProviderData.Builder {
ctor public CreateCredentialProviderData.Builder(@NonNull String);
- method @NonNull public android.credentials.ui.CreateCredentialProviderData build();
- method @NonNull public android.credentials.ui.CreateCredentialProviderData.Builder setRemoteEntry(@Nullable android.credentials.ui.Entry);
- method @NonNull public android.credentials.ui.CreateCredentialProviderData.Builder setSaveEntries(@NonNull java.util.List<android.credentials.ui.Entry>);
+ method @NonNull public android.credentials.selection.CreateCredentialProviderData build();
+ method @NonNull public android.credentials.selection.CreateCredentialProviderData.Builder setRemoteEntry(@Nullable android.credentials.selection.Entry);
+ method @NonNull public android.credentials.selection.CreateCredentialProviderData.Builder setSaveEntries(@NonNull java.util.List<android.credentials.selection.Entry>);
}
- public final class DisabledProviderData extends android.credentials.ui.ProviderData implements android.os.Parcelable {
+ @FlaggedApi("android.credentials.flags.configurable_selector_ui_enabled") public final class DisabledProviderData extends android.credentials.selection.ProviderData implements android.os.Parcelable {
ctor public DisabledProviderData(@NonNull String);
- field @NonNull public static final android.os.Parcelable.Creator<android.credentials.ui.DisabledProviderData> CREATOR;
+ field @NonNull public static final android.os.Parcelable.Creator<android.credentials.selection.DisabledProviderData> CREATOR;
}
- public final class Entry implements android.os.Parcelable {
+ @FlaggedApi("android.credentials.flags.configurable_selector_ui_enabled") public final class Entry implements android.os.Parcelable {
ctor public Entry(@NonNull String, @NonNull String, @NonNull android.app.slice.Slice);
ctor public Entry(@NonNull String, @NonNull String, @NonNull android.app.slice.Slice, @NonNull android.content.Intent);
method public int describeContents();
@@ -1309,56 +1327,81 @@
method @NonNull public android.app.slice.Slice getSlice();
method @NonNull public String getSubkey();
method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.credentials.ui.Entry> CREATOR;
+ field @NonNull public static final android.os.Parcelable.Creator<android.credentials.selection.Entry> CREATOR;
}
- public final class GetCredentialProviderData extends android.credentials.ui.ProviderData implements android.os.Parcelable {
- ctor public GetCredentialProviderData(@NonNull String, @NonNull java.util.List<android.credentials.ui.Entry>, @NonNull java.util.List<android.credentials.ui.Entry>, @NonNull java.util.List<android.credentials.ui.AuthenticationEntry>, @Nullable android.credentials.ui.Entry);
- method @NonNull public java.util.List<android.credentials.ui.Entry> getActionChips();
- method @NonNull public java.util.List<android.credentials.ui.AuthenticationEntry> getAuthenticationEntries();
- method @NonNull public java.util.List<android.credentials.ui.Entry> getCredentialEntries();
- method @Nullable public android.credentials.ui.Entry getRemoteEntry();
- field @NonNull public static final android.os.Parcelable.Creator<android.credentials.ui.GetCredentialProviderData> CREATOR;
+ @FlaggedApi("android.credentials.flags.configurable_selector_ui_enabled") public final class FailureDialogResult extends android.credentials.selection.BaseDialogResult implements android.os.Parcelable {
+ ctor public FailureDialogResult(@Nullable android.os.IBinder, @Nullable String);
+ method public static void addToBundle(@NonNull android.credentials.selection.FailureDialogResult, @NonNull android.os.Bundle);
+ method @Nullable public static android.credentials.selection.FailureDialogResult fromResultData(@NonNull android.os.Bundle);
+ method @Nullable public String getErrorMessage();
+ field @NonNull public static final android.os.Parcelable.Creator<android.credentials.selection.FailureDialogResult> CREATOR;
}
- public static final class GetCredentialProviderData.Builder {
+ @FlaggedApi("android.credentials.flags.configurable_selector_ui_enabled") public final class GetCredentialProviderData extends android.credentials.selection.ProviderData implements android.os.Parcelable {
+ ctor public GetCredentialProviderData(@NonNull String, @NonNull java.util.List<android.credentials.selection.Entry>, @NonNull java.util.List<android.credentials.selection.Entry>, @NonNull java.util.List<android.credentials.selection.AuthenticationEntry>, @Nullable android.credentials.selection.Entry);
+ method @NonNull public java.util.List<android.credentials.selection.Entry> getActionChips();
+ method @NonNull public java.util.List<android.credentials.selection.AuthenticationEntry> getAuthenticationEntries();
+ method @NonNull public java.util.List<android.credentials.selection.Entry> getCredentialEntries();
+ method @Nullable public android.credentials.selection.Entry getRemoteEntry();
+ field @NonNull public static final android.os.Parcelable.Creator<android.credentials.selection.GetCredentialProviderData> CREATOR;
+ }
+
+ @FlaggedApi("android.credentials.flags.configurable_selector_ui_enabled") public static final class GetCredentialProviderData.Builder {
ctor public GetCredentialProviderData.Builder(@NonNull String);
- method @NonNull public android.credentials.ui.GetCredentialProviderData build();
- method @NonNull public android.credentials.ui.GetCredentialProviderData.Builder setActionChips(@NonNull java.util.List<android.credentials.ui.Entry>);
- method @NonNull public android.credentials.ui.GetCredentialProviderData.Builder setAuthenticationEntries(@NonNull java.util.List<android.credentials.ui.AuthenticationEntry>);
- method @NonNull public android.credentials.ui.GetCredentialProviderData.Builder setCredentialEntries(@NonNull java.util.List<android.credentials.ui.Entry>);
- method @NonNull public android.credentials.ui.GetCredentialProviderData.Builder setRemoteEntry(@Nullable android.credentials.ui.Entry);
+ method @NonNull public android.credentials.selection.GetCredentialProviderData build();
+ method @NonNull public android.credentials.selection.GetCredentialProviderData.Builder setActionChips(@NonNull java.util.List<android.credentials.selection.Entry>);
+ method @NonNull public android.credentials.selection.GetCredentialProviderData.Builder setAuthenticationEntries(@NonNull java.util.List<android.credentials.selection.AuthenticationEntry>);
+ method @NonNull public android.credentials.selection.GetCredentialProviderData.Builder setCredentialEntries(@NonNull java.util.List<android.credentials.selection.Entry>);
+ method @NonNull public android.credentials.selection.GetCredentialProviderData.Builder setRemoteEntry(@Nullable android.credentials.selection.Entry);
}
- public class IntentFactory {
- method @NonNull public static android.content.Intent createCredentialSelectorIntent(@NonNull android.credentials.ui.RequestInfo, @NonNull java.util.ArrayList<android.credentials.ui.ProviderData>, @NonNull java.util.ArrayList<android.credentials.ui.DisabledProviderData>, @NonNull android.os.ResultReceiver);
+ @FlaggedApi("android.credentials.flags.configurable_selector_ui_enabled") public class IntentFactory {
+ method @NonNull public static android.content.Intent createCredentialSelectorIntent(@NonNull android.credentials.selection.RequestInfo, @NonNull java.util.ArrayList<android.credentials.selection.ProviderData>, @NonNull java.util.ArrayList<android.credentials.selection.DisabledProviderData>, @NonNull android.os.ResultReceiver);
}
- public abstract class ProviderData implements android.os.Parcelable {
+ @FlaggedApi("android.credentials.flags.configurable_selector_ui_enabled") public abstract class ProviderData implements android.os.Parcelable {
ctor public ProviderData(@NonNull String);
ctor protected ProviderData(@NonNull android.os.Parcel);
method public int describeContents();
method @NonNull public String getProviderFlattenedComponentName();
method public void writeToParcel(@NonNull android.os.Parcel, int);
- field public static final String EXTRA_DISABLED_PROVIDER_DATA_LIST = "android.credentials.ui.extra.DISABLED_PROVIDER_DATA_LIST";
- field public static final String EXTRA_ENABLED_PROVIDER_DATA_LIST = "android.credentials.ui.extra.ENABLED_PROVIDER_DATA_LIST";
+ field public static final String EXTRA_DISABLED_PROVIDER_DATA_LIST = "android.credentials.selection.extra.DISABLED_PROVIDER_DATA_LIST";
+ field public static final String EXTRA_ENABLED_PROVIDER_DATA_LIST = "android.credentials.selection.extra.ENABLED_PROVIDER_DATA_LIST";
}
- public final class RequestInfo implements android.os.Parcelable {
+ @FlaggedApi("android.credentials.flags.configurable_selector_ui_enabled") public final class RequestInfo implements android.os.Parcelable {
method public int describeContents();
method @NonNull public String getAppPackageName();
method @Nullable public android.credentials.CreateCredentialRequest getCreateCredentialRequest();
+ method @NonNull public java.util.List<java.lang.String> getDefaultProviderIds();
method @Nullable public android.credentials.GetCredentialRequest getGetCredentialRequest();
+ method @NonNull public java.util.List<java.lang.String> getRegistryProviderIds();
method @NonNull public android.os.IBinder getToken();
method @NonNull public String getType();
- method @NonNull public static android.credentials.ui.RequestInfo newCreateRequestInfo(@NonNull android.os.IBinder, @NonNull android.credentials.CreateCredentialRequest, @NonNull String);
- method @NonNull public static android.credentials.ui.RequestInfo newGetRequestInfo(@NonNull android.os.IBinder, @NonNull android.credentials.GetCredentialRequest, @NonNull String);
+ method public boolean hasPermissionToOverrideDefault();
+ method @NonNull public static android.credentials.selection.RequestInfo newCreateRequestInfo(@NonNull android.os.IBinder, @NonNull android.credentials.CreateCredentialRequest, @NonNull String);
+ method @NonNull public static android.credentials.selection.RequestInfo newCreateRequestInfo(@NonNull android.os.IBinder, @NonNull android.credentials.CreateCredentialRequest, @NonNull String, boolean, @NonNull java.util.List<java.lang.String>);
+ method @NonNull public static android.credentials.selection.RequestInfo newGetRequestInfo(@NonNull android.os.IBinder, @NonNull android.credentials.GetCredentialRequest, @NonNull String, boolean);
+ method @NonNull public static android.credentials.selection.RequestInfo newGetRequestInfo(@NonNull android.os.IBinder, @NonNull android.credentials.GetCredentialRequest, @NonNull String);
method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.credentials.ui.RequestInfo> CREATOR;
- field @NonNull public static final String EXTRA_REQUEST_INFO = "android.credentials.ui.extra.REQUEST_INFO";
- field @NonNull public static final String TYPE_CREATE = "android.credentials.ui.TYPE_CREATE";
- field @NonNull public static final String TYPE_GET = "android.credentials.ui.TYPE_GET";
- field @NonNull public static final String TYPE_UNDEFINED = "android.credentials.ui.TYPE_UNDEFINED";
+ field @NonNull public static final android.os.Parcelable.Creator<android.credentials.selection.RequestInfo> CREATOR;
+ field @NonNull public static final String EXTRA_REQUEST_INFO = "android.credentials.selection.extra.REQUEST_INFO";
+ field @NonNull public static final String TYPE_CREATE = "android.credentials.selection.TYPE_CREATE";
+ field @NonNull public static final String TYPE_GET = "android.credentials.selection.TYPE_GET";
+ field @NonNull public static final String TYPE_UNDEFINED = "android.credentials.selection.TYPE_UNDEFINED";
+ }
+
+ @FlaggedApi("android.credentials.flags.configurable_selector_ui_enabled") public final class UserSelectionDialogResult extends android.credentials.selection.BaseDialogResult implements android.os.Parcelable {
+ ctor public UserSelectionDialogResult(@Nullable android.os.IBinder, @NonNull String, @NonNull String, @NonNull String);
+ ctor public UserSelectionDialogResult(@Nullable android.os.IBinder, @NonNull String, @NonNull String, @NonNull String, @Nullable android.credentials.selection.ProviderPendingIntentResponse);
+ method public static void addToBundle(@NonNull android.credentials.selection.UserSelectionDialogResult, @NonNull android.os.Bundle);
+ method @Nullable public static android.credentials.selection.UserSelectionDialogResult fromResultData(@NonNull android.os.Bundle);
+ method @NonNull public String getEntryKey();
+ method @NonNull public String getEntrySubkey();
+ method @Nullable public android.credentials.selection.ProviderPendingIntentResponse getPendingIntentProviderResponse();
+ method @NonNull public String getProviderId();
+ field @NonNull public static final android.os.Parcelable.Creator<android.credentials.selection.UserSelectionDialogResult> CREATOR;
}
}
@@ -2068,6 +2111,14 @@
}
+package android.media.projection {
+
+ public final class MediaProjectionManager {
+ method @NonNull public android.content.Intent createScreenCaptureIntent(@Nullable android.app.ActivityOptions.LaunchCookie);
+ }
+
+}
+
package android.media.soundtrigger {
public final class SoundTriggerInstrumentation {
@@ -3646,6 +3697,7 @@
public interface WindowManager extends android.view.ViewManager {
method public default int getDisplayImePolicy(int);
+ method @FlaggedApi("com.android.window.flags.surface_control_input_receiver") @Nullable public default android.os.IBinder getSurfaceControlInputClientToken(@NonNull android.view.SurfaceControl);
method public static boolean hasWindowExtensionsEnabled();
method public default void holdLock(android.os.IBinder, int);
method public default boolean isGlobalKey(int);
diff --git a/core/java/android/app/ActivityOptions.aidl b/core/java/android/app/ActivityOptions.aidl
index bd5cd88..2d4a85f 100644
--- a/core/java/android/app/ActivityOptions.aidl
+++ b/core/java/android/app/ActivityOptions.aidl
@@ -17,4 +17,7 @@
package android.app;
/** @hide */
-parcelable ActivityOptions.SceneTransitionInfo;
\ No newline at end of file
+parcelable ActivityOptions.SceneTransitionInfo;
+
+/** @hide */
+parcelable ActivityOptions.LaunchCookie;
\ No newline at end of file
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index 57fca74..111895e 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -184,6 +184,12 @@
public static final String KEY_ANIM_START_LISTENER = "android:activity.animStartListener";
/**
+ * Callback for when animation is aborted.
+ * @hide
+ */
+ private static final String KEY_ANIM_ABORT_LISTENER = "android:activity.animAbortListener";
+
+ /**
* Specific a theme for a splash screen window.
* @hide
*/
@@ -459,6 +465,7 @@
private int mHeight;
private IRemoteCallback mAnimationStartedListener;
private IRemoteCallback mAnimationFinishedListener;
+ private IRemoteCallback mAnimationAbortListener;
private SceneTransitionInfo mSceneTransitionInfo;
private PendingIntent mUsageTimeReport;
private int mLaunchDisplayId = INVALID_DISPLAY;
@@ -716,6 +723,14 @@
}
/**
+ * Callback for finding out when the given animation is finished
+ * @hide
+ */
+ public void setOnAnimationFinishedListener(IRemoteCallback listener) {
+ mAnimationFinishedListener = listener;
+ }
+
+ /**
* Callback for finding out when the given animation has drawn its last frame.
* @hide
*/
@@ -728,6 +743,14 @@
}
/**
+ * Callback for finding out when the given animation is aborted
+ * @hide
+ */
+ public void setOnAnimationAbortListener(IRemoteCallback listener) {
+ mAnimationAbortListener = listener;
+ }
+
+ /**
* Create an ActivityOptions specifying an animation where the new
* activity is scaled from a small originating area of the screen to
* its final full representation.
@@ -1327,6 +1350,8 @@
KEY_PENDING_INTENT_CREATOR_BACKGROUND_ACTIVITY_START_MODE,
MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED);
mDisableStartingWindow = opts.getBoolean(KEY_DISABLE_STARTING_WINDOW);
+ mAnimationAbortListener = IRemoteCallback.Stub.asInterface(
+ opts.getBinder(KEY_ANIM_ABORT_LISTENER));
}
/**
@@ -1427,11 +1452,15 @@
/** @hide */
public void abort() {
- if (mAnimationStartedListener != null) {
+ sendResultIgnoreErrors(mAnimationStartedListener, null);
+ sendResultIgnoreErrors(mAnimationAbortListener, null);
+ }
+
+ private void sendResultIgnoreErrors(IRemoteCallback callback, Bundle data) {
+ if (callback != null) {
try {
- mAnimationStartedListener.sendResult(null);
- } catch (RemoteException e) {
- }
+ callback.sendResult(data);
+ } catch (RemoteException e) { }
}
}
@@ -1929,14 +1958,87 @@
*/
@SuppressLint("UnflaggedApi")
@TestApi
- public static final class LaunchCookie {
+ public static final class LaunchCookie implements Parcelable {
/** @hide */
- public final IBinder binder = new Binder();
+ public final IBinder binder;
/** @hide */
@SuppressLint("UnflaggedApi")
@TestApi
- public LaunchCookie() {}
+ public LaunchCookie() {
+ binder = new Binder();
+ }
+
+ /** @hide */
+ public LaunchCookie(@Nullable String descriptor) {
+ binder = new Binder(descriptor);
+ }
+
+ private LaunchCookie(Parcel in) {
+ this.binder = in.readStrongBinder();
+ }
+
+ /** @hide */
+ @SuppressLint("UnflaggedApi")
+ @TestApi
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /** @hide */
+ @SuppressLint("UnflaggedApi")
+ @TestApi
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeStrongBinder(binder);
+ }
+
+ /** @hide */
+ public static LaunchCookie readFromParcel(@NonNull Parcel in) {
+ return new LaunchCookie(in);
+ }
+
+ /** @hide */
+ public static void writeToParcel(@Nullable LaunchCookie launchCookie, Parcel out) {
+ if (launchCookie != null) {
+ launchCookie.writeToParcel(out, 0);
+ } else {
+ out.writeStrongBinder(null);
+ }
+ }
+
+ /** @hide */
+ @SuppressLint("UnflaggedApi")
+ @TestApi
+ @NonNull
+ public static final Parcelable.Creator<LaunchCookie> CREATOR =
+ new Parcelable.Creator<LaunchCookie>() {
+
+ @Override
+ public LaunchCookie createFromParcel(Parcel source) {
+ return new LaunchCookie(source);
+ }
+
+ @Override
+ public LaunchCookie[] newArray(int size) {
+ return new LaunchCookie[size];
+ }
+ };
+
+ @Override
+ public boolean equals(@Nullable Object obj) {
+ if (obj instanceof LaunchCookie) {
+ LaunchCookie other = (LaunchCookie) obj;
+ return binder == other.binder;
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return binder.hashCode();
+ }
}
/**
@@ -2110,12 +2212,7 @@
mCustomExitResId = otherOptions.mCustomExitResId;
mCustomBackgroundColor = otherOptions.mCustomBackgroundColor;
mThumbnail = null;
- if (mAnimationStartedListener != null) {
- try {
- mAnimationStartedListener.sendResult(null);
- } catch (RemoteException e) {
- }
- }
+ sendResultIgnoreErrors(mAnimationStartedListener, null);
mAnimationStartedListener = otherOptions.mAnimationStartedListener;
break;
case ANIM_CUSTOM_IN_PLACE:
@@ -2126,12 +2223,7 @@
mStartY = otherOptions.mStartY;
mWidth = otherOptions.mWidth;
mHeight = otherOptions.mHeight;
- if (mAnimationStartedListener != null) {
- try {
- mAnimationStartedListener.sendResult(null);
- } catch (RemoteException e) {
- }
- }
+ sendResultIgnoreErrors(mAnimationStartedListener, null);
mAnimationStartedListener = null;
break;
case ANIM_THUMBNAIL_SCALE_UP:
@@ -2143,12 +2235,7 @@
mStartY = otherOptions.mStartY;
mWidth = otherOptions.mWidth;
mHeight = otherOptions.mHeight;
- if (mAnimationStartedListener != null) {
- try {
- mAnimationStartedListener.sendResult(null);
- } catch (RemoteException e) {
- }
- }
+ sendResultIgnoreErrors(mAnimationStartedListener, null);
mAnimationStartedListener = otherOptions.mAnimationStartedListener;
break;
case ANIM_SCENE_TRANSITION:
@@ -2165,6 +2252,9 @@
mRemoteAnimationAdapter = otherOptions.mRemoteAnimationAdapter;
mLaunchIntoPipParams = otherOptions.mLaunchIntoPipParams;
mIsEligibleForLegacyPermissionPrompt = otherOptions.mIsEligibleForLegacyPermissionPrompt;
+
+ sendResultIgnoreErrors(mAnimationAbortListener, null);
+ mAnimationAbortListener = otherOptions.mAnimationAbortListener;
}
/**
@@ -2363,6 +2453,8 @@
if (mDisableStartingWindow) {
b.putBoolean(KEY_DISABLE_STARTING_WINDOW, mDisableStartingWindow);
}
+ b.putBinder(KEY_ANIM_ABORT_LISTENER,
+ mAnimationAbortListener != null ? mAnimationAbortListener.asBinder() : null);
return b;
}
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 1bdbd4c5..5d2a26e 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -319,6 +319,10 @@
public static final int SERVICE_DONE_EXECUTING_START = 1;
/** Type for IActivityManager.serviceDoneExecuting: done stopping (destroying) service */
public static final int SERVICE_DONE_EXECUTING_STOP = 2;
+ /** Type for IActivityManager.serviceDoneExecuting: done with an onRebind call */
+ public static final int SERVICE_DONE_EXECUTING_REBIND = 3;
+ /** Type for IActivityManager.serviceDoneExecuting: done with an onUnbind call */
+ public static final int SERVICE_DONE_EXECUTING_UNBIND = 4;
/** Use foreground GC policy (less pause time) and higher JIT weight. */
private static final int VM_PROCESS_STATE_JANK_PERCEPTIBLE = 0;
@@ -4882,7 +4886,7 @@
mServices.put(data.token, service);
try {
ActivityManager.getService().serviceDoneExecuting(
- data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
+ data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0, null);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -4913,7 +4917,7 @@
} else {
s.onRebind(data.intent);
ActivityManager.getService().serviceDoneExecuting(
- data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
+ data.token, SERVICE_DONE_EXECUTING_REBIND, 0, 0, data.intent);
}
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
@@ -4943,7 +4947,7 @@
data.token, data.intent, doRebind);
} else {
ActivityManager.getService().serviceDoneExecuting(
- data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
+ data.token, SERVICE_DONE_EXECUTING_UNBIND, 0, 0, data.intent);
}
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
@@ -5057,7 +5061,7 @@
try {
ActivityManager.getService().serviceDoneExecuting(
- data.token, SERVICE_DONE_EXECUTING_START, data.startId, res);
+ data.token, SERVICE_DONE_EXECUTING_START, data.startId, res, null);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -5089,7 +5093,7 @@
try {
ActivityManager.getService().serviceDoneExecuting(
- token, SERVICE_DONE_EXECUTING_STOP, 0, 0);
+ token, SERVICE_DONE_EXECUTING_STOP, 0, 0, null);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index ed00d9c..b0f6c46 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -240,7 +240,7 @@
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private final String mOpPackageName;
private final @NonNull ContextParams mParams;
- private final @NonNull AttributionSource mAttributionSource;
+ private @NonNull AttributionSource mAttributionSource;
private final @NonNull ResourcesManager mResourcesManager;
@UnsupportedAppUsage
@@ -2630,10 +2630,9 @@
flags | CONTEXT_REGISTER_PACKAGE);
if (pi != null) {
ContextImpl c = new ContextImpl(this, mMainThread, pi, ContextParams.EMPTY,
- mAttributionSource.getAttributionTag(),
- mAttributionSource.getNext(),
- null, mToken, new UserHandle(UserHandle.getUserId(application.uid)),
- flags, null, null);
+ mAttributionSource.getAttributionTag(), mAttributionSource.getNext(), null,
+ mToken, new UserHandle(UserHandle.getUserId(application.uid)), flags, null,
+ null, mDeviceId, mIsExplicitDeviceId);
final int displayId = getDisplayId();
final Integer overrideDisplayId = mForceDisplayOverrideInResources
@@ -2679,18 +2678,16 @@
// The system resources are loaded in every application, so we can safely copy
// the context without reloading Resources.
return new ContextImpl(this, mMainThread, mPackageInfo, mParams,
- mAttributionSource.getAttributionTag(),
- mAttributionSource.getNext(),
- null, mToken, user, flags, null, null);
+ mAttributionSource.getAttributionTag(), mAttributionSource.getNext(), null,
+ mToken, user, flags, null, null, mDeviceId, mIsExplicitDeviceId);
}
LoadedApk pi = mMainThread.getPackageInfo(packageName, mResources.getCompatibilityInfo(),
flags | CONTEXT_REGISTER_PACKAGE, user.getIdentifier());
if (pi != null) {
ContextImpl c = new ContextImpl(this, mMainThread, pi, mParams,
- mAttributionSource.getAttributionTag(),
- mAttributionSource.getNext(),
- null, mToken, user, flags, null, null);
+ mAttributionSource.getAttributionTag(), mAttributionSource.getNext(), null,
+ mToken, user, flags, null, null, mDeviceId, mIsExplicitDeviceId);
final int displayId = getDisplayId();
final Integer overrideDisplayId = mForceDisplayOverrideInResources
@@ -2729,9 +2726,8 @@
final String[] paths = mPackageInfo.getSplitPaths(splitName);
final ContextImpl context = new ContextImpl(this, mMainThread, mPackageInfo, mParams,
- mAttributionSource.getAttributionTag(),
- mAttributionSource.getNext(),
- splitName, mToken, mUser, mFlags, classLoader, null);
+ mAttributionSource.getAttributionTag(), mAttributionSource.getNext(), splitName,
+ mToken, mUser, mFlags, classLoader, null, mDeviceId, mIsExplicitDeviceId);
context.setResources(ResourcesManager.getInstance().getResources(
mToken,
@@ -2765,9 +2761,9 @@
}
ContextImpl context = new ContextImpl(this, mMainThread, mPackageInfo, mParams,
- mAttributionSource.getAttributionTag(),
- mAttributionSource.getNext(),
- mSplitName, mToken, mUser, mFlags, mClassLoader, null);
+ mAttributionSource.getAttributionTag(), mAttributionSource.getNext(), mSplitName,
+ mToken, mUser, mFlags, mClassLoader, null, mDeviceId,
+ mIsExplicitDeviceId);
context.mIsConfigurationBasedContext = true;
final int displayId = getDisplayId();
@@ -2786,9 +2782,8 @@
}
ContextImpl context = new ContextImpl(this, mMainThread, mPackageInfo, mParams,
- mAttributionSource.getAttributionTag(),
- mAttributionSource.getNext(),
- mSplitName, mToken, mUser, mFlags, mClassLoader, null);
+ mAttributionSource.getAttributionTag(), mAttributionSource.getNext(), mSplitName,
+ mToken, mUser, mFlags, mClassLoader, null, mDeviceId, mIsExplicitDeviceId);
final int displayId = display.getDisplayId();
@@ -2833,14 +2828,9 @@
}
}
- ContextImpl context = new ContextImpl(this, mMainThread, mPackageInfo, mParams,
- mAttributionSource.getAttributionTag(),
- mAttributionSource.getNext(),
- mSplitName, mToken, mUser, mFlags, mClassLoader, null);
-
- context.mDeviceId = deviceId;
- context.mIsExplicitDeviceId = true;
- return context;
+ return new ContextImpl(this, mMainThread, mPackageInfo, mParams,
+ mAttributionSource.getAttributionTag(), mAttributionSource.getNext(), mSplitName,
+ mToken, mUser, mFlags, mClassLoader, null, deviceId, true);
}
@NonNull
@@ -2926,9 +2916,8 @@
@UiContext
ContextImpl createWindowContextBase(@NonNull IBinder token, int displayId) {
ContextImpl baseContext = new ContextImpl(this, mMainThread, mPackageInfo, mParams,
- mAttributionSource.getAttributionTag(),
- mAttributionSource.getNext(),
- mSplitName, token, mUser, mFlags, mClassLoader, null);
+ mAttributionSource.getAttributionTag(), mAttributionSource.getNext(), mSplitName,
+ token, mUser, mFlags, mClassLoader, null, mDeviceId, mIsExplicitDeviceId);
// Window contexts receive configurations directly from the server and as such do not
// need to override their display in ResourcesManager.
baseContext.mForceDisplayOverrideInResources = false;
@@ -2979,7 +2968,8 @@
public Context createContext(@NonNull ContextParams contextParams) {
return new ContextImpl(this, mMainThread, mPackageInfo, contextParams,
contextParams.getAttributionTag(), contextParams.getNextAttributionSource(),
- mSplitName, mToken, mUser, mFlags, mClassLoader, null);
+ mSplitName, mToken, mUser, mFlags, mClassLoader, null, mDeviceId,
+ mIsExplicitDeviceId);
}
@Override
@@ -2993,9 +2983,8 @@
final int flags = (mFlags & ~Context.CONTEXT_CREDENTIAL_PROTECTED_STORAGE)
| Context.CONTEXT_DEVICE_PROTECTED_STORAGE;
return new ContextImpl(this, mMainThread, mPackageInfo, mParams,
- mAttributionSource.getAttributionTag(),
- mAttributionSource.getNext(),
- mSplitName, mToken, mUser, flags, mClassLoader, null);
+ mAttributionSource.getAttributionTag(), mAttributionSource.getNext(), mSplitName,
+ mToken, mUser, flags, mClassLoader, null, mDeviceId, mIsExplicitDeviceId);
}
@Override
@@ -3003,9 +2992,8 @@
final int flags = (mFlags & ~Context.CONTEXT_DEVICE_PROTECTED_STORAGE)
| Context.CONTEXT_CREDENTIAL_PROTECTED_STORAGE;
return new ContextImpl(this, mMainThread, mPackageInfo, mParams,
- mAttributionSource.getAttributionTag(),
- mAttributionSource.getNext(),
- mSplitName, mToken, mUser, flags, mClassLoader, null);
+ mAttributionSource.getAttributionTag(), mAttributionSource.getNext(), mSplitName,
+ mToken, mUser, flags, mClassLoader, null, mDeviceId, mIsExplicitDeviceId);
}
@Override
@@ -3098,6 +3086,7 @@
int deviceId = vdm.getDeviceIdForDisplayId(displayId);
if (deviceId != mDeviceId) {
mDeviceId = deviceId;
+ mAttributionSource = mAttributionSource.withDeviceId(mDeviceId);
notifyOnDeviceChangedListeners(mDeviceId);
}
}
@@ -3298,7 +3287,8 @@
static ContextImpl createSystemContext(ActivityThread mainThread) {
LoadedApk packageInfo = new LoadedApk(mainThread);
ContextImpl context = new ContextImpl(null, mainThread, packageInfo,
- ContextParams.EMPTY, null, null, null, null, null, 0, null, null);
+ ContextParams.EMPTY, null, null, null, null, null, 0, null, null,
+ DEVICE_ID_DEFAULT, false);
context.setResources(packageInfo.getResources());
context.mResources.updateConfiguration(context.mResourcesManager.getConfiguration(),
context.mResourcesManager.getDisplayMetrics());
@@ -3333,7 +3323,8 @@
String opPackageName) {
if (packageInfo == null) throw new IllegalArgumentException("packageInfo");
ContextImpl context = new ContextImpl(null, mainThread, packageInfo,
- ContextParams.EMPTY, null, null, null, null, null, 0, null, opPackageName);
+ ContextParams.EMPTY, null, null, null, null, null, 0, null, opPackageName,
+ DEVICE_ID_DEFAULT, false);
context.setResources(packageInfo.getResources());
context.mContextType = isSystemOrSystemUI(context) ? CONTEXT_TYPE_SYSTEM_OR_SYSTEM_UI
: CONTEXT_TYPE_NON_UI;
@@ -3371,7 +3362,7 @@
ContextImpl context = new ContextImpl(null, mainThread, packageInfo, ContextParams.EMPTY,
attributionTag, null, activityInfo.splitName, activityToken, null, 0, classLoader,
- null);
+ null, DEVICE_ID_DEFAULT, false);
context.mContextType = CONTEXT_TYPE_ACTIVITY;
context.mIsConfigurationBasedContext = true;
@@ -3407,7 +3398,8 @@
@NonNull LoadedApk packageInfo, @NonNull ContextParams params,
@Nullable String attributionTag, @Nullable AttributionSource nextAttributionSource,
@Nullable String splitName, @Nullable IBinder token, @Nullable UserHandle user,
- int flags, @Nullable ClassLoader classLoader, @Nullable String overrideOpPackageName) {
+ int flags, @Nullable ClassLoader classLoader, @Nullable String overrideOpPackageName,
+ int deviceId, boolean isExplicitDeviceId) {
mOuterContext = this;
// If creator didn't specify which storage to use, use the default
// location for application.
@@ -3437,13 +3429,18 @@
String opPackageName;
+ mDeviceId = deviceId;
+ mIsExplicitDeviceId = isExplicitDeviceId;
+
if (container != null) {
mBasePackageName = container.mBasePackageName;
opPackageName = container.mOpPackageName;
setResources(container.mResources);
mDisplay = container.mDisplay;
- mDeviceId = container.mDeviceId;
- mIsExplicitDeviceId = container.mIsExplicitDeviceId;
+ if (!isExplicitDeviceId) {
+ mIsExplicitDeviceId = container.mIsExplicitDeviceId;
+ mDeviceId = container.mDeviceId;
+ }
mForceDisplayOverrideInResources = container.mForceDisplayOverrideInResources;
mIsConfigurationBasedContext = container.mIsConfigurationBasedContext;
mContextType = container.mContextType;
@@ -3466,17 +3463,18 @@
mOpPackageName = overrideOpPackageName != null ? overrideOpPackageName : opPackageName;
mParams = Objects.requireNonNull(params);
mAttributionSource = createAttributionSource(attributionTag, nextAttributionSource,
- params.getRenouncedPermissions(), params.shouldRegisterAttributionSource());
+ params.getRenouncedPermissions(), params.shouldRegisterAttributionSource(), mDeviceId);
mContentResolver = new ApplicationContentResolver(this, mainThread);
}
private @NonNull AttributionSource createAttributionSource(@Nullable String attributionTag,
@Nullable AttributionSource nextAttributionSource,
- @Nullable Set<String> renouncedPermissions, boolean shouldRegister) {
+ @Nullable Set<String> renouncedPermissions, boolean shouldRegister,
+ int deviceId) {
AttributionSource attributionSource = new AttributionSource(Process.myUid(),
Process.myPid(), mOpPackageName, attributionTag,
(renouncedPermissions != null) ? renouncedPermissions.toArray(new String[0]) : null,
- getDeviceId(), nextAttributionSource);
+ deviceId, nextAttributionSource);
// If we want to access protected data on behalf of another app we need to
// tell the OS that we opt in to participate in the attribution chain.
if (nextAttributionSource != null || shouldRegister) {
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 47403d2..b063d04 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -294,7 +294,8 @@
@UnsupportedAppUsage
ParceledListSlice getRecentTasks(int maxNum, int flags, int userId);
@UnsupportedAppUsage
- oneway void serviceDoneExecuting(in IBinder token, int type, int startId, int res);
+ oneway void serviceDoneExecuting(in IBinder token, int type, int startId, int res,
+ in Intent intent);
/** @deprecated Use {@link #getIntentSenderWithFeature} instead */
@UnsupportedAppUsage(maxTargetSdk=29, publicAlternatives="Use {@link PendingIntent#getIntentSender()} instead")
IIntentSender getIntentSender(int type, in String packageName, in IBinder token,
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index 2162e3a..68512b8 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -79,6 +79,7 @@
* implementation is described to the system through an AndroidManifest.xml's
* <instrumentation> tag.
*/
+@android.ravenwood.annotation.RavenwoodKeepPartialClass
public class Instrumentation {
/**
@@ -132,6 +133,7 @@
private UiAutomation mUiAutomation;
private final Object mAnimationCompleteLock = new Object();
+ @android.ravenwood.annotation.RavenwoodKeep
public Instrumentation() {
}
@@ -142,6 +144,7 @@
* reflection, but it will serve as noticeable discouragement from
* doing such a thing.
*/
+ @android.ravenwood.annotation.RavenwoodReplace
private void checkInstrumenting(String method) {
// Check if we have an instrumentation context, as init should only get called by
// the system in startup processes that are being instrumented.
@@ -151,6 +154,11 @@
}
}
+ private void checkInstrumenting$ravenwood(String method) {
+ // At the moment, Ravenwood doesn't attach a Context, but we're only ever
+ // running code as part of tests, so we continue quietly
+ }
+
/**
* Returns if it is being called in an instrumentation environment.
*
@@ -2504,6 +2512,7 @@
* Takes control of the execution of messages on the specified looper until
* {@link TestLooperManager#release} is called.
*/
+ @android.ravenwood.annotation.RavenwoodKeep
public TestLooperManager acquireLooperManager(Looper looper) {
checkInstrumenting("acquireLooperManager");
return new TestLooperManager(looper);
diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java
index 0261f0a..1ac08ac 100644
--- a/core/java/android/app/PendingIntent.java
+++ b/core/java/android/app/PendingIntent.java
@@ -179,6 +179,14 @@
@Overridable
public static final long BLOCK_MUTABLE_IMPLICIT_PENDING_INTENT = 236704164L;
+ /**
+ * Validate options passed in as bundle.
+ * @hide
+ */
+ @ChangeId
+ @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ public static final long PENDING_INTENT_OPTIONS_CHECK = 320664730L;
+
/** @hide */
@IntDef(flag = true,
value = {
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index d755413..397b63f 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -210,6 +210,7 @@
import android.permission.PermissionManager;
import android.print.IPrintManager;
import android.print.PrintManager;
+import android.provider.ContactKeysManager;
import android.safetycenter.SafetyCenterFrameworkInitializer;
import android.scheduling.SchedulingFrameworkInitializer;
import android.security.FileIntegrityManager;
@@ -1604,6 +1605,18 @@
}
});
+ registerService(Context.CONTACT_KEYS_SERVICE, ContactKeysManager.class,
+ new CachedServiceFetcher<ContactKeysManager>() {
+ @Override
+ public ContactKeysManager createService(ContextImpl ctx)
+ throws ServiceNotFoundException {
+ if (!android.provider.Flags.userKeys()) {
+ throw new ServiceNotFoundException(
+ "ContactKeysManager is not supported");
+ }
+ return new ContactKeysManager(ctx);
+ }});
+
sInitializing = true;
try {
// Note: the following functions need to be @SystemApis, once they become mainline
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 5c42b0e..86d0125 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -53,6 +53,7 @@
import static android.content.Intent.LOCAL_FLAG_FROM_SYSTEM;
import static android.net.NetworkCapabilities.NET_ENTERPRISE_ID_1;
import static android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE;
+import static android.view.contentprotection.flags.Flags.FLAG_MANAGE_DEVICE_POLICY_ENABLED;
import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
@@ -61,6 +62,7 @@
import android.annotation.BroadcastBehavior;
import android.annotation.CallbackExecutor;
import android.annotation.ColorInt;
+import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -4092,6 +4094,29 @@
return MTE_NOT_CONTROLLED_BY_POLICY;
}
+ /** Indicates that content protection is not controlled by policy, allowing user to choose. */
+ @FlaggedApi(FLAG_MANAGE_DEVICE_POLICY_ENABLED)
+ public static final int CONTENT_PROTECTION_NOT_CONTROLLED_BY_POLICY = 0;
+
+ /** Indicates that content protection is controlled and disabled by a policy. */
+ @FlaggedApi(FLAG_MANAGE_DEVICE_POLICY_ENABLED)
+ public static final int CONTENT_PROTECTION_DISABLED = 1;
+
+ /** Indicates that content protection is controlled and enabled by a policy. */
+ @FlaggedApi(FLAG_MANAGE_DEVICE_POLICY_ENABLED)
+ public static final int CONTENT_PROTECTION_ENABLED = 2;
+
+ /** @hide */
+ @IntDef(
+ prefix = {"CONTENT_PROTECTION_"},
+ value = {
+ CONTENT_PROTECTION_NOT_CONTROLLED_BY_POLICY,
+ CONTENT_PROTECTION_DISABLED,
+ CONTENT_PROTECTION_ENABLED,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ContentProtectionPolicy {}
+
/**
* This object is a single place to tack on invalidation and disable calls. All
* binder caches in this class derive from this Config, so all can be invalidated or
diff --git a/core/java/android/appwidget/AppWidgetHostView.java b/core/java/android/appwidget/AppWidgetHostView.java
index ec181da..1f19f81 100644
--- a/core/java/android/appwidget/AppWidgetHostView.java
+++ b/core/java/android/appwidget/AppWidgetHostView.java
@@ -907,7 +907,10 @@
private InteractionHandler getHandler(InteractionHandler handler) {
return (view, pendingIntent, response) -> {
- AppWidgetManager.getInstance(mContext).noteAppWidgetTapped(mAppWidgetId);
+ AppWidgetManager manager = AppWidgetManager.getInstance(mContext);
+ if (manager != null) {
+ manager.noteAppWidgetTapped(mAppWidgetId);
+ }
if (handler != null) {
return handler.onInteraction(view, pendingIntent, response);
} else {
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 67a3627..b8d7543 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -3657,8 +3657,8 @@
* On Android {@link android.os.Build.VERSION_CODES#S} and later,
* if the application is in a state where the service
* can not be started (such as not in the foreground in a state when services are allowed),
- * {@link android.app.BackgroundServiceStartNotAllowedException} is thrown
- * This excemption extends {@link IllegalStateException}, so apps can
+ * {@link android.app.BackgroundServiceStartNotAllowedException} is thrown.
+ * This exception extends {@link IllegalStateException}, so apps can
* use {@code catch (IllegalStateException)} to catch both.
*
* @see #startForegroundService(Intent)
@@ -4243,6 +4243,7 @@
GRAMMATICAL_INFLECTION_SERVICE,
SECURITY_STATE_SERVICE,
//@hide: ECM_ENHANCED_CONFIRMATION_SERVICE,
+ CONTACT_KEYS_SERVICE,
})
@Retention(RetentionPolicy.SOURCE)
@@ -6542,6 +6543,16 @@
public static final String ECM_ENHANCED_CONFIRMATION_SERVICE = "ecm_enhanced_confirmation";
/**
+ * Use with {@link #getSystemService(String)} to retrieve a
+ * {@link android.provider.ContactKeysManager} to managing contact keys.
+ *
+ * @see #getSystemService(String)
+ * @see android.provider.ContactKeysManager
+ */
+ @FlaggedApi(android.provider.Flags.FLAG_USER_KEYS)
+ public static final String CONTACT_KEYS_SERVICE = "contact_keys";
+
+ /**
* Determine whether the given permission is allowed for a particular
* process and user ID running in the system.
*
diff --git a/core/java/android/content/IntentFilter.java b/core/java/android/content/IntentFilter.java
index ad3acd7..79af65a 100644
--- a/core/java/android/content/IntentFilter.java
+++ b/core/java/android/content/IntentFilter.java
@@ -16,11 +16,13 @@
package android.content;
+import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.compat.annotation.UnsupportedAppUsage;
+import android.content.pm.Flags;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
@@ -175,6 +177,7 @@
private static final String ACTION_STR = "action";
private static final String AUTO_VERIFY_STR = "autoVerify";
private static final String EXTRAS_STR = "extras";
+ private static final String URI_RELATIVE_FILTER_GROUP_STR = "uriRelativeFilterGroup";
private static final int[] EMPTY_INT_ARRAY = new int[0];
private static final long[] EMPTY_LONG_ARRAY = new long[0];
@@ -324,6 +327,7 @@
private ArrayList<PatternMatcher> mDataSchemeSpecificParts = null;
private ArrayList<AuthorityEntry> mDataAuthorities = null;
private ArrayList<PatternMatcher> mDataPaths = null;
+ private ArrayList<UriRelativeFilterGroup> mUriRelativeFilterGroups = null;
private ArrayList<String> mStaticDataTypes = null;
private ArrayList<String> mDataTypes = null;
private ArrayList<String> mMimeGroups = null;
@@ -520,6 +524,10 @@
if (o.mDataPaths != null) {
mDataPaths = new ArrayList<PatternMatcher>(o.mDataPaths);
}
+ if (o.mUriRelativeFilterGroups != null) {
+ mUriRelativeFilterGroups =
+ new ArrayList<UriRelativeFilterGroup>(o.mUriRelativeFilterGroups);
+ }
if (o.mMimeGroups != null) {
mMimeGroups = new ArrayList<String>(o.mMimeGroups);
}
@@ -1563,6 +1571,63 @@
}
/**
+ * Add a new URI relative filter group to match against the Intent data. The
+ * intent filter must include one or more schemes (via {@link #addDataScheme})
+ * <em>and</em> one or more authorities (via {@link #addDataAuthority}) for
+ * the group to be considered.
+ *
+ * <p>Groups will be matched in the order they were added and matching will only
+ * be done if no data paths match or if none are included. If both data paths and
+ * groups are not included, then only the scheme/authority must match.</p>
+ *
+ * @param group A {@link UriRelativeFilterGroup} to match the URI.
+ *
+ * @see UriRelativeFilterGroup
+ * @see #matchData
+ * @see #addDataScheme
+ * @see #addDataAuthority
+ */
+ @FlaggedApi(Flags.FLAG_RELATIVE_REFERENCE_INTENT_FILTERS)
+ public final void addUriRelativeFilterGroup(@NonNull UriRelativeFilterGroup group) {
+ Objects.requireNonNull(group);
+ if (mUriRelativeFilterGroups == null) {
+ mUriRelativeFilterGroups = new ArrayList<>();
+ }
+ mUriRelativeFilterGroups.add(group);
+ }
+
+ /**
+ * Return the number of URI relative filter groups in the intent filter.
+ */
+ @FlaggedApi(Flags.FLAG_RELATIVE_REFERENCE_INTENT_FILTERS)
+ public final int countUriRelativeFilterGroups() {
+ return mUriRelativeFilterGroups == null ? 0 : mUriRelativeFilterGroups.size();
+ }
+
+ /**
+ * Return a URI relative filter group in the intent filter.
+ *
+ * <p>Note: use of this method will result in a NullPointerException
+ * if no groups exists for this intent filter.</p>
+ *
+ * @param index index of the element to return
+ * @throws IndexOutOfBoundsException if index is out of range
+ */
+ @FlaggedApi(Flags.FLAG_RELATIVE_REFERENCE_INTENT_FILTERS)
+ @NonNull
+ public final UriRelativeFilterGroup getUriRelativeFilterGroup(int index) {
+ return mUriRelativeFilterGroups.get(index);
+ }
+
+ /**
+ * Removes all existing URI relative filter groups in the intent filter.
+ */
+ @FlaggedApi(Flags.FLAG_RELATIVE_REFERENCE_INTENT_FILTERS)
+ public final void clearUriRelativeFilterGroups() {
+ mUriRelativeFilterGroups = null;
+ }
+
+ /**
* Match this intent filter against the given Intent data. This ignores
* the data scheme -- unlike {@link #matchData}, the authority will match
* regardless of whether there is a matching scheme.
@@ -1677,12 +1742,24 @@
int authMatch = matchDataAuthority(data, wildcardSupported);
if (authMatch >= 0) {
final ArrayList<PatternMatcher> paths = mDataPaths;
- if (paths == null) {
- match = authMatch;
- } else if (hasDataPath(data.getPath(), wildcardSupported)) {
- match = MATCH_CATEGORY_PATH;
+ final ArrayList<UriRelativeFilterGroup> groups = mUriRelativeFilterGroups;
+ if (Flags.relativeReferenceIntentFilters()) {
+ if (paths == null && groups == null) {
+ match = authMatch;
+ } else if (hasDataPath(data.getPath(), wildcardSupported)
+ || matchRelRefGroups(data)) {
+ match = MATCH_CATEGORY_PATH;
+ } else {
+ return NO_MATCH_DATA;
+ }
} else {
- return NO_MATCH_DATA;
+ if (paths == null) {
+ match = authMatch;
+ } else if (hasDataPath(data.getPath(), wildcardSupported)) {
+ match = MATCH_CATEGORY_PATH;
+ } else {
+ return NO_MATCH_DATA;
+ }
}
} else {
return NO_MATCH_DATA;
@@ -1726,6 +1803,19 @@
return match + MATCH_ADJUSTMENT_NORMAL;
}
+ private boolean matchRelRefGroups(Uri data) {
+ if (mUriRelativeFilterGroups == null) {
+ return false;
+ }
+ for (int i = 0; i < mUriRelativeFilterGroups.size(); i++) {
+ UriRelativeFilterGroup group = mUriRelativeFilterGroups.get(i);
+ if (group.matchData(data)) {
+ return group.getAction() == UriRelativeFilterGroup.ACTION_ALLOW;
+ }
+ }
+ return false;
+ }
+
/**
* Add a new Intent category to match against. The semantics of
* categories is the opposite of actions -- an Intent includes the
@@ -2486,6 +2576,12 @@
}
serializer.endTag(null, EXTRAS_STR);
}
+ if (Flags.relativeReferenceIntentFilters()) {
+ N = countUriRelativeFilterGroups();
+ for (int i = 0; i < N; i++) {
+ mUriRelativeFilterGroups.get(i).writeToXml(serializer);
+ }
+ }
}
/**
@@ -2614,6 +2710,9 @@
}
} else if (tagName.equals(EXTRAS_STR)) {
mExtras = PersistableBundle.restoreFromXml(parser);
+ } else if (Flags.relativeReferenceIntentFilters()
+ && URI_RELATIVE_FILTER_GROUP_STR.equals(tagName)) {
+ addUriRelativeFilterGroup(new UriRelativeFilterGroup(parser));
} else {
Log.w("IntentFilter", "Unknown tag parsing IntentFilter: " + tagName);
}
@@ -2680,6 +2779,12 @@
if (mExtras != null) {
mExtras.dumpDebug(proto, IntentFilterProto.EXTRAS);
}
+ if (Flags.relativeReferenceIntentFilters() && mUriRelativeFilterGroups != null) {
+ Iterator<UriRelativeFilterGroup> it = mUriRelativeFilterGroups.iterator();
+ while (it.hasNext()) {
+ it.next().dumpDebug(proto, IntentFilterProto.URI_RELATIVE_FILTER_GROUPS);
+ }
+ }
proto.end(token);
}
@@ -2744,6 +2849,15 @@
du.println(sb.toString());
}
}
+ if (mUriRelativeFilterGroups != null) {
+ Iterator<UriRelativeFilterGroup> it = mUriRelativeFilterGroups.iterator();
+ while (it.hasNext()) {
+ sb.setLength(0);
+ sb.append(prefix); sb.append("UriRelativeFilterGroup: \"");
+ sb.append(it.next()); sb.append("\"");
+ du.println(sb.toString());
+ }
+ }
if (mStaticDataTypes != null) {
Iterator<String> it = mStaticDataTypes.iterator();
while (it.hasNext()) {
@@ -2883,6 +2997,15 @@
} else {
dest.writeInt(0);
}
+ if (Flags.relativeReferenceIntentFilters() && mUriRelativeFilterGroups != null) {
+ final int N = mUriRelativeFilterGroups.size();
+ dest.writeInt(N);
+ for (int i = 0; i < N; i++) {
+ mUriRelativeFilterGroups.get(i).writeToParcel(dest, flags);
+ }
+ } else {
+ dest.writeInt(0);
+ }
}
/**
@@ -2989,6 +3112,13 @@
if (source.readInt() != 0) {
mExtras = PersistableBundle.CREATOR.createFromParcel(source);
}
+ N = source.readInt();
+ if (Flags.relativeReferenceIntentFilters() && N > 0) {
+ mUriRelativeFilterGroups = new ArrayList<UriRelativeFilterGroup>(N);
+ for (int i = 0; i < N; i++) {
+ mUriRelativeFilterGroups.add(new UriRelativeFilterGroup(source));
+ }
+ }
}
private boolean hasPartialTypes() {
diff --git a/core/java/android/content/UriRelativeFilter.java b/core/java/android/content/UriRelativeFilter.java
new file mode 100644
index 0000000..9866cd0
--- /dev/null
+++ b/core/java/android/content/UriRelativeFilter.java
@@ -0,0 +1,260 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content;
+
+import android.annotation.FlaggedApi;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.pm.Flags;
+import android.net.Uri;
+import android.os.Parcel;
+import android.os.PatternMatcher;
+import android.util.proto.ProtoOutputStream;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.IOException;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * A filter for matching Intent URI Data as part of a
+ * {@link UriRelativeFilterGroup}. A single filter can only be
+ * matched against either a URI path, query or fragment
+ */
+@FlaggedApi(Flags.FLAG_RELATIVE_REFERENCE_INTENT_FILTERS)
+public final class UriRelativeFilter {
+ private static final String FILTER_STR = "filter";
+ private static final String PART_STR = "part";
+ private static final String PATTERN_STR = "pattern";
+ static final String URI_RELATIVE_FILTER_STR = "uriRelativeFilter";
+
+ /**
+ * Value to indicate that the filter is to be applied to a URI path.
+ */
+ public static final int PATH = 0;
+ /**
+ * Value to indicate that the filter is to be applied to a URI query.
+ */
+ public static final int QUERY = 1;
+ /**
+ * Value to indicate that the filter is to be applied to a URI fragment.
+ */
+ public static final int FRAGMENT = 2;
+
+ /** @hide */
+ @IntDef(value = {
+ PATH,
+ QUERY,
+ FRAGMENT
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface UriPart {}
+
+ private final @UriPart int mUriPart;
+ private final @PatternMatcher.PatternType int mPatternType;
+ private final String mFilter;
+
+ /**
+ * Creates a new UriRelativeFilter.
+ *
+ * @param uriPart The URI part this filter operates on. Can be either a
+ * {@link UriRelativeFilter#PATH}, {@link UriRelativeFilter#QUERY},
+ * or {@link UriRelativeFilter#FRAGMENT}.
+ * @param patternType The pattern type of the filter. Can be either a
+ * {@link PatternMatcher#PATTERN_LITERAL},
+ * {@link PatternMatcher#PATTERN_PREFIX},
+* {@link PatternMatcher#PATTERN_SUFFIX},
+ * {@link PatternMatcher#PATTERN_SIMPLE_GLOB},
+ * or {@link PatternMatcher#PATTERN_ADVANCED_GLOB}.
+ * @param filter A literal or pattern string depedning on patterType
+ * used to match a uriPart .
+ */
+ public UriRelativeFilter(
+ @UriPart int uriPart,
+ @PatternMatcher.PatternType int patternType,
+ @NonNull String filter) {
+ mUriPart = uriPart;
+ com.android.internal.util.AnnotationValidations.validate(
+ UriPart.class, null, mUriPart);
+ mPatternType = patternType;
+ com.android.internal.util.AnnotationValidations.validate(
+ PatternMatcher.PatternType.class, null, mPatternType);
+ mFilter = filter;
+ com.android.internal.util.AnnotationValidations.validate(
+ NonNull.class, null, mFilter);
+ }
+
+ /**
+ * The URI part this filter operates on.
+ */
+ public @UriPart int getUriPart() {
+ return mUriPart;
+ }
+
+ /**
+ * The pattern type of the filter.
+ */
+ public @PatternMatcher.PatternType int getPatternType() {
+ return mPatternType;
+ }
+
+ /**
+ * The string used to filter the URI.
+ */
+ public @NonNull String getFilter() {
+ return mFilter;
+ }
+
+ /**
+ * Match this URI filter against an Intent's data. QUERY filters can
+ * match against any key value pair in the query string. PATH and
+ * FRAGMENT filters must match the entire string.
+ *
+ * @param data The full data string to match against, as supplied in
+ * Intent.data.
+ *
+ * @return true if there is a match.
+ */
+ public boolean matchData(@NonNull Uri data) {
+ PatternMatcher pe = new PatternMatcher(mFilter, mPatternType);
+ switch (getUriPart()) {
+ case PATH:
+ return pe.match(data.getPath());
+ case QUERY:
+ return matchQuery(pe, data.getQuery());
+ case FRAGMENT:
+ return pe.match(data.getFragment());
+ default:
+ return false;
+ }
+ }
+
+ private boolean matchQuery(PatternMatcher pe, String query) {
+ if (query != null) {
+ String[] params = query.split("&");
+ if (params.length == 1) {
+ params = query.split(";");
+ }
+ for (int i = 0; i < params.length; i++) {
+ if (pe.match(params[i])) return true;
+ }
+ }
+ return false;
+ }
+
+ /** @hide */
+ public void dumpDebug(ProtoOutputStream proto, long fieldId) {
+ long token = proto.start(fieldId);
+ proto.write(UriRelativeFilterProto.URI_PART, mUriPart);
+ proto.write(UriRelativeFilterProto.PATTERN_TYPE, mPatternType);
+ proto.write(UriRelativeFilterProto.FILTER, mFilter);
+ proto.end(token);
+ }
+
+ /** @hide */
+ public void writeToXml(XmlSerializer serializer) throws IOException {
+ serializer.startTag(null, URI_RELATIVE_FILTER_STR);
+ serializer.attribute(null, PATTERN_STR, Integer.toString(mPatternType));
+ serializer.attribute(null, PART_STR, Integer.toString(mUriPart));
+ serializer.attribute(null, FILTER_STR, mFilter);
+ serializer.endTag(null, URI_RELATIVE_FILTER_STR);
+ }
+
+ private String uriPartToString() {
+ switch (mUriPart) {
+ case PATH:
+ return "PATH";
+ case QUERY:
+ return "QUERY";
+ case FRAGMENT:
+ return "FRAGMENT";
+ default:
+ return "UNKNOWN";
+ }
+ }
+
+ private String patternTypeToString() {
+ switch (mPatternType) {
+ case PatternMatcher.PATTERN_LITERAL:
+ return "LITERAL";
+ case PatternMatcher.PATTERN_PREFIX:
+ return "PREFIX";
+ case PatternMatcher.PATTERN_SIMPLE_GLOB:
+ return "GLOB";
+ case PatternMatcher.PATTERN_ADVANCED_GLOB:
+ return "ADVANCED_GLOB";
+ case PatternMatcher.PATTERN_SUFFIX:
+ return "SUFFIX";
+ default:
+ return "UNKNOWN";
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "UriRelativeFilter { "
+ + "uriPart = " + uriPartToString() + ", "
+ + "patternType = " + patternTypeToString() + ", "
+ + "filter = " + mFilter
+ + " }";
+ }
+
+ @Override
+ public boolean equals(@Nullable Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ @SuppressWarnings("unchecked")
+ UriRelativeFilter that = (UriRelativeFilter) o;
+ return mUriPart == that.mUriPart
+ && mPatternType == that.mPatternType
+ && java.util.Objects.equals(mFilter, that.mFilter);
+ }
+
+ @Override
+ public int hashCode() {
+ int _hash = 1;
+ _hash = 31 * _hash + mUriPart;
+ _hash = 31 * _hash + mPatternType;
+ _hash = 31 * _hash + java.util.Objects.hashCode(mFilter);
+ return _hash;
+ }
+
+ /** @hide */
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeInt(mUriPart);
+ dest.writeInt(mPatternType);
+ dest.writeString(mFilter);
+ }
+
+ /** @hide */
+ UriRelativeFilter(@NonNull android.os.Parcel in) {
+ mUriPart = in.readInt();
+ mPatternType = in.readInt();
+ mFilter = in.readString();
+ }
+
+ /** @hide */
+ public UriRelativeFilter(XmlPullParser parser) throws XmlPullParserException, IOException {
+ mUriPart = Integer.parseInt(parser.getAttributeValue(null, PART_STR));
+ mPatternType = Integer.parseInt(parser.getAttributeValue(null, PATTERN_STR));
+ mFilter = parser.getAttributeValue(null, FILTER_STR);
+ }
+}
diff --git a/core/java/android/content/UriRelativeFilterGroup.java b/core/java/android/content/UriRelativeFilterGroup.java
new file mode 100644
index 0000000..72c396a
--- /dev/null
+++ b/core/java/android/content/UriRelativeFilterGroup.java
@@ -0,0 +1,216 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content;
+
+import android.annotation.FlaggedApi;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.content.pm.Flags;
+import android.net.Uri;
+import android.os.Parcel;
+import android.util.ArraySet;
+import android.util.Log;
+import android.util.proto.ProtoOutputStream;
+
+import com.android.internal.util.CollectionUtils;
+import com.android.internal.util.XmlUtils;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.IOException;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.Objects;
+
+/**
+ * An intent data matching group based on a URI's relative reference which
+ * includes the path, query and fragment. The group is only considered as
+ * matching if <em>all</em> UriRelativeFilters in the group match. Each
+ * UriRelativeFilter defines a matching rule for a URI path, query or fragment.
+ * A group must contain one or more UriRelativeFilters to match but does not need to
+ * contain UriRelativeFilters for all existing parts of a URI to match.
+ *
+ * <p>For example, given a URI that contains path, query and fragment parts,
+ * a group containing only a path filter will match the URI if the path
+ * filter matches the URI path. If the group contains a path and query
+ * filter, then the group will only match if both path and query filters
+ * match. If a URI contains only a path with no query or fragment then a
+ * group can only match if it contains only a matching path filter. If the
+ * group also contained additional query or fragment filters then it will
+ * not match.</p>
+ */
+@FlaggedApi(Flags.FLAG_RELATIVE_REFERENCE_INTENT_FILTERS)
+public final class UriRelativeFilterGroup {
+ private static final String ALLOW_STR = "allow";
+ private static final String URI_RELATIVE_FILTER_GROUP_STR = "uriRelativeFilterGroup";
+
+ /**
+ * Value to indicate that the group match is allowed.
+ */
+ public static final int ACTION_ALLOW = 0;
+ /**
+ * Value to indicate that the group match is blocked.
+ */
+ public static final int ACTION_BLOCK = 1;
+
+ /** @hide */
+ @IntDef(value = {
+ ACTION_ALLOW,
+ ACTION_BLOCK
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Action {}
+
+ private final @Action int mAction;
+ private final ArraySet<UriRelativeFilter> mUriRelativeFilters = new ArraySet<>();
+
+ /**
+ * New UriRelativeFilterGroup that matches a Intent data.
+ *
+ * @param action Whether this matching group should be allowed or disallowed.
+ */
+ public UriRelativeFilterGroup(@Action int action) {
+ mAction = action;
+ }
+
+ /** @hide */
+ public UriRelativeFilterGroup(XmlPullParser parser) throws XmlPullParserException, IOException {
+ mAction = Integer.parseInt(parser.getAttributeValue(null, ALLOW_STR));
+
+ int outerDepth = parser.getDepth();
+ int type;
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG
+ || parser.getDepth() > outerDepth)) {
+ if (type == XmlPullParser.END_TAG
+ || type == XmlPullParser.TEXT) {
+ continue;
+ }
+
+ String tagName = parser.getName();
+ if (tagName.equals(UriRelativeFilter.URI_RELATIVE_FILTER_STR)) {
+ addUriRelativeFilter(new UriRelativeFilter(parser));
+ } else {
+ Log.w("IntentFilter", "Unknown tag parsing IntentFilter: " + tagName);
+ }
+ XmlUtils.skipCurrentTag(parser);
+ }
+ }
+
+ /**
+ * Return {@link UriRelativeFilterGroup#ACTION_ALLOW} if a URI is allowed when matched
+ * and {@link UriRelativeFilterGroup#ACTION_BLOCK} if a URI is blacked when matched.
+ */
+ public @Action int getAction() {
+ return mAction;
+ }
+
+ /**
+ * Add a filter to the group.
+ */
+ public void addUriRelativeFilter(@NonNull UriRelativeFilter uriRelativeFilter) {
+ Objects.requireNonNull(uriRelativeFilter);
+ if (!CollectionUtils.contains(mUriRelativeFilters, uriRelativeFilter)) {
+ mUriRelativeFilters.add(uriRelativeFilter);
+ }
+ }
+
+ /**
+ * Returns a unmodifiable view of the UriRelativeFilters list in this group.
+ */
+ @NonNull
+ public Collection<UriRelativeFilter> getUriRelativeFilters() {
+ return Collections.unmodifiableCollection(mUriRelativeFilters);
+ }
+
+ /**
+ * Match all URI filter in this group against {@link Intent#getData()}.
+ *
+ * @param data The full data string to match against, as supplied in
+ * Intent.data.
+ * @return true if all filters match.
+ */
+ public boolean matchData(@NonNull Uri data) {
+ if (mUriRelativeFilters.size() == 0) {
+ return false;
+ }
+ for (UriRelativeFilter filter : mUriRelativeFilters) {
+ if (!filter.matchData(data)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /** @hide */
+ public void dumpDebug(ProtoOutputStream proto, long fieldId) {
+ long token = proto.start(fieldId);
+ proto.write(UriRelativeFilterGroupProto.ACTION, mAction);
+ Iterator<UriRelativeFilter> it = mUriRelativeFilters.iterator();
+ while (it.hasNext()) {
+ it.next().dumpDebug(proto, UriRelativeFilterGroupProto.URI_RELATIVE_FILTERS);
+ }
+ proto.end(token);
+ }
+
+ /** @hide */
+ public void writeToXml(XmlSerializer serializer) throws IOException {
+ serializer.startTag(null, URI_RELATIVE_FILTER_GROUP_STR);
+ serializer.attribute(null, ALLOW_STR, Integer.toString(mAction));
+ Iterator<UriRelativeFilter> it = mUriRelativeFilters.iterator();
+ while (it.hasNext()) {
+ UriRelativeFilter filter = it.next();
+ filter.writeToXml(serializer);
+ }
+ serializer.endTag(null, URI_RELATIVE_FILTER_GROUP_STR);
+ }
+
+ @Override
+ public String toString() {
+ return "UriRelativeFilterGroup { allow = " + mAction
+ + ", uri_filters = " + mUriRelativeFilters + ", }";
+ }
+
+ /** @hide */
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeInt(mAction);
+ final int n = mUriRelativeFilters.size();
+ if (n > 0) {
+ dest.writeInt(n);
+ Iterator<UriRelativeFilter> it = mUriRelativeFilters.iterator();
+ while (it.hasNext()) {
+ it.next().writeToParcel(dest, flags);
+ }
+ } else {
+ dest.writeInt(0);
+ }
+ }
+
+ /** @hide */
+ UriRelativeFilterGroup(@NonNull Parcel src) {
+ mAction = src.readInt();
+ final int n = src.readInt();
+ for (int i = 0; i < n; i++) {
+ mUriRelativeFilters.add(new UriRelativeFilter(src));
+ }
+ }
+}
diff --git a/core/java/android/content/pm/UserProperties.java b/core/java/android/content/pm/UserProperties.java
index 269c6c2..1d0e2db 100644
--- a/core/java/android/content/pm/UserProperties.java
+++ b/core/java/android/content/pm/UserProperties.java
@@ -16,6 +16,9 @@
package android.content.pm;
+import static android.multiuser.Flags.FLAG_SUPPORT_HIDING_PROFILES;
+
+import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -73,7 +76,7 @@
private static final String ATTR_CROSS_PROFILE_CONTENT_SHARING_STRATEGY =
"crossProfileContentSharingStrategy";
-
+ private static final String ATTR_PROFILE_API_VISIBILITY = "profileApiVisibility";
/** Index values of each property (to indicate whether they are present in this object). */
@IntDef(prefix = "INDEX_", value = {
INDEX_SHOW_IN_LAUNCHER,
@@ -93,6 +96,7 @@
INDEX_AUTH_ALWAYS_REQUIRED_TO_DISABLE_QUIET_MODE,
INDEX_CROSS_PROFILE_CONTENT_SHARING_STRATEGY,
INDEX_ALLOW_STOPPING_USER_WITH_DELAYED_LOCKING,
+ INDEX_PROFILE_API_VISIBILITY
})
@Retention(RetentionPolicy.SOURCE)
private @interface PropertyIndex {
@@ -114,6 +118,7 @@
private static final int INDEX_SHOW_IN_SHARING_SURFACES = 14;
private static final int INDEX_CROSS_PROFILE_CONTENT_SHARING_STRATEGY = 15;
private static final int INDEX_ALLOW_STOPPING_USER_WITH_DELAYED_LOCKING = 16;
+ private static final int INDEX_PROFILE_API_VISIBILITY = 17;
/** A bit set, mapping each PropertyIndex to whether it is present (1) or absent (0). */
private long mPropertiesPresent = 0;
@@ -450,6 +455,41 @@
@SuppressLint("UnflaggedApi") // b/306636213
public static final int CROSS_PROFILE_CONTENT_SHARING_DELEGATE_FROM_PARENT = 1;
+ /**
+ * Possible values for the profile visibility in public API surfaces. This indicates whether or
+ * not the information linked to the profile (userId, package names) should not be returned in
+ * API surfaces if a user is marked as hidden.
+ *
+ * @hide
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = "PROFILE_API_VISIBILITY_",
+ value = {
+ PROFILE_API_VISIBILITY_UNKNOWN,
+ PROFILE_API_VISIBILITY_VISIBLE,
+ PROFILE_API_VISIBILITY_HIDDEN,
+ }
+ )
+ public @interface ProfileApiVisibility {
+ }
+ /*
+ * The api visibility value for this profile user is undefined or unknown.
+ */
+ @FlaggedApi(FLAG_SUPPORT_HIDING_PROFILES)
+ public static final int PROFILE_API_VISIBILITY_UNKNOWN = -1;
+
+ /**
+ * Indicates that information about this profile user should be shown in API surfaces.
+ */
+ @FlaggedApi(FLAG_SUPPORT_HIDING_PROFILES)
+ public static final int PROFILE_API_VISIBILITY_VISIBLE = 0;
+
+ /**
+ * Indicates that information about this profile should be not be visible in API surfaces.
+ */
+ @FlaggedApi(FLAG_SUPPORT_HIDING_PROFILES)
+ public static final int PROFILE_API_VISIBILITY_HIDDEN = 1;
+
/**
* Creates a UserProperties (intended for the SystemServer) that stores a reference to the given
@@ -510,6 +550,9 @@
setShowInQuietMode(orig.getShowInQuietMode());
setShowInSharingSurfaces(orig.getShowInSharingSurfaces());
setCrossProfileContentSharingStrategy(orig.getCrossProfileContentSharingStrategy());
+ if (android.multiuser.Flags.supportHidingProfiles()) {
+ setProfileApiVisibility(orig.getProfileApiVisibility());
+ }
}
/**
@@ -951,9 +994,31 @@
}
private @CrossProfileContentSharingStrategy int mCrossProfileContentSharingStrategy;
+ /**
+ * Returns the visibility of the profile user in API surfaces. Any information linked to the
+ * profile (userId, package names) should be hidden API surfaces if a user is marked as hidden.
+ */
+ @NonNull
+ @FlaggedApi(FLAG_SUPPORT_HIDING_PROFILES)
+ public @ProfileApiVisibility int getProfileApiVisibility() {
+ if (isPresent(INDEX_PROFILE_API_VISIBILITY)) return mProfileApiVisibility;
+ if (mDefaultProperties != null) return mDefaultProperties.mProfileApiVisibility;
+ throw new SecurityException("You don't have permission to query profileApiVisibility");
+ }
+ /** @hide */
+ @NonNull
+ @FlaggedApi(FLAG_SUPPORT_HIDING_PROFILES)
+ public void setProfileApiVisibility(@ProfileApiVisibility int profileApiVisibility) {
+ this.mProfileApiVisibility = profileApiVisibility;
+ setPresent(INDEX_PROFILE_API_VISIBILITY);
+ }
+ private @ProfileApiVisibility int mProfileApiVisibility;
@Override
public String toString() {
+ String profileApiVisibility =
+ android.multiuser.Flags.supportHidingProfiles() ? ", mProfileApiVisibility="
+ + getProfileApiVisibility() : "";
// Please print in increasing order of PropertyIndex.
return "UserProperties{"
+ "mPropertiesPresent=" + Long.toBinaryString(mPropertiesPresent)
@@ -977,6 +1042,7 @@
+ ", mDeleteAppWithParent=" + getDeleteAppWithParent()
+ ", mAlwaysVisible=" + getAlwaysVisible()
+ ", mCrossProfileContentSharingStrategy=" + getCrossProfileContentSharingStrategy()
+ + profileApiVisibility
+ "}";
}
@@ -1010,6 +1076,9 @@
pw.println(prefix + " mAlwaysVisible=" + getAlwaysVisible());
pw.println(prefix + " mCrossProfileContentSharingStrategy="
+ getCrossProfileContentSharingStrategy());
+ if (android.multiuser.Flags.supportHidingProfiles()) {
+ pw.println(prefix + " mProfileApiVisibility=" + getProfileApiVisibility());
+ }
}
/**
@@ -1093,6 +1162,12 @@
break;
case ATTR_CROSS_PROFILE_CONTENT_SHARING_STRATEGY:
setCrossProfileContentSharingStrategy(parser.getAttributeInt(i));
+ break;
+ case ATTR_PROFILE_API_VISIBILITY:
+ if (android.multiuser.Flags.supportHidingProfiles()) {
+ setProfileApiVisibility(parser.getAttributeInt(i));
+ }
+ break;
default:
Slog.w(LOG_TAG, "Skipping unknown property " + attributeName);
}
@@ -1175,6 +1250,12 @@
serializer.attributeInt(null, ATTR_CROSS_PROFILE_CONTENT_SHARING_STRATEGY,
mCrossProfileContentSharingStrategy);
}
+ if (isPresent(INDEX_PROFILE_API_VISIBILITY)) {
+ if (android.multiuser.Flags.supportHidingProfiles()) {
+ serializer.attributeInt(null, ATTR_PROFILE_API_VISIBILITY,
+ mProfileApiVisibility);
+ }
+ }
}
// For use only with an object that has already had any permission-lacking fields stripped out.
@@ -1198,6 +1279,7 @@
dest.writeBoolean(mDeleteAppWithParent);
dest.writeBoolean(mAlwaysVisible);
dest.writeInt(mCrossProfileContentSharingStrategy);
+ dest.writeInt(mProfileApiVisibility);
}
/**
@@ -1225,6 +1307,7 @@
mDeleteAppWithParent = source.readBoolean();
mAlwaysVisible = source.readBoolean();
mCrossProfileContentSharingStrategy = source.readInt();
+ mProfileApiVisibility = source.readInt();
}
@Override
@@ -1274,6 +1357,7 @@
private boolean mAlwaysVisible = false;
private @CrossProfileContentSharingStrategy int mCrossProfileContentSharingStrategy =
CROSS_PROFILE_CONTENT_SHARING_NO_DELEGATION;
+ private @ProfileApiVisibility int mProfileApiVisibility = 0;
/**
* @hide
@@ -1428,6 +1512,17 @@
return this;
}
+ /**
+ * Sets the value for {@link #mProfileApiVisibility}
+ * @hide
+ */
+ @NonNull
+ @FlaggedApi(FLAG_SUPPORT_HIDING_PROFILES)
+ public Builder setProfileApiVisibility(@ProfileApiVisibility int profileApiVisibility){
+ mProfileApiVisibility = profileApiVisibility;
+ return this;
+ }
+
/** Builds a UserProperties object with *all* values populated.
* @hide
*/
@@ -1452,7 +1547,8 @@
mAllowStoppingUserWithDelayedLocking,
mDeleteAppWithParent,
mAlwaysVisible,
- mCrossProfileContentSharingStrategy);
+ mCrossProfileContentSharingStrategy,
+ mProfileApiVisibility);
}
} // end Builder
@@ -1473,7 +1569,8 @@
boolean allowStoppingUserWithDelayedLocking,
boolean deleteAppWithParent,
boolean alwaysVisible,
- @CrossProfileContentSharingStrategy int crossProfileContentSharingStrategy) {
+ @CrossProfileContentSharingStrategy int crossProfileContentSharingStrategy,
+ @ProfileApiVisibility int profileApiVisibility) {
mDefaultProperties = null;
setShowInLauncher(showInLauncher);
setStartWithParent(startWithParent);
@@ -1493,5 +1590,8 @@
setDeleteAppWithParent(deleteAppWithParent);
setAlwaysVisible(alwaysVisible);
setCrossProfileContentSharingStrategy(crossProfileContentSharingStrategy);
+ if (android.multiuser.Flags.supportHidingProfiles()) {
+ setProfileApiVisibility(profileApiVisibility);
+ }
}
}
diff --git a/core/java/android/content/pm/flags.aconfig b/core/java/android/content/pm/flags.aconfig
index fd87290..caff457 100644
--- a/core/java/android/content/pm/flags.aconfig
+++ b/core/java/android/content/pm/flags.aconfig
@@ -110,6 +110,14 @@
}
flag {
+ name: "relative_reference_intent_filters"
+ namespace: "package_manager_service"
+ description: "Feature flag to enable relative reference intent filters"
+ bug: "307556883"
+ is_fixed_read_only: true
+}
+
+flag {
name: "fix_duplicated_flags"
namespace: "package_manager_service"
description: "Feature flag to fix duplicated PackageManager flag values"
@@ -168,3 +176,10 @@
description: "Feature flag to allow the sandbox SDK to query intent activities of the client app."
bug: "295842134"
}
+
+flag {
+ name: "emergency_install_permission"
+ namespace: "permissions"
+ description: "Feature flag to enable permission EMERGENCY_INSTALL_PACKAGES"
+ bug: "321080601"
+}
diff --git a/core/java/android/content/pm/multiuser.aconfig b/core/java/android/content/pm/multiuser.aconfig
index c083437..efb8607 100644
--- a/core/java/android/content/pm/multiuser.aconfig
+++ b/core/java/android/content/pm/multiuser.aconfig
@@ -100,3 +100,11 @@
description: "Enable only the API changes to support private space"
bug: "299069460"
}
+
+flag {
+ name: "support_hiding_profiles"
+ namespace: "profile_experiences"
+ description: "Allow the use of a hide_profile property to hide some profiles behind a permission"
+ bug: "316362775"
+ is_fixed_read_only: true
+}
diff --git a/core/java/android/content/res/Element.java b/core/java/android/content/res/Element.java
index 89f4985..6ff96f4 100644
--- a/core/java/android/content/res/Element.java
+++ b/core/java/android/content/res/Element.java
@@ -93,6 +93,7 @@
protected static final String TAG_SUPPORTS_GL_TEXTURE = "supports-gl-texture";
protected static final String TAG_SUPPORTS_INPUT = "supports-input";
protected static final String TAG_SUPPORTS_SCREENS = "supports-screens";
+ protected static final String TAG_URI_RELATIVE_FILTER_GROUP = "uri-relative-filter-group";
protected static final String TAG_USES_CONFIGURATION = "uses-configuration";
protected static final String TAG_USES_FEATURE = "uses-feature";
protected static final String TAG_USES_GL_TEXTURE = "uses-gl-texture";
@@ -106,6 +107,11 @@
protected static final String TAG_ATTR_BACKUP_AGENT = "backupAgent";
protected static final String TAG_ATTR_CATEGORY = "category";
+ protected static final String TAG_ATTR_FRAGMENT = "fragment";
+ protected static final String TAG_ATTR_FRAGMENT_ADVANCED_PATTERN = "fragmentAdvancedPattern";
+ protected static final String TAG_ATTR_FRAGMENT_PATTERN = "fragmentPattern";
+ protected static final String TAG_ATTR_FRAGMENT_PREFIX = "fragmentPrefix";
+ protected static final String TAG_ATTR_FRAGMENT_SUFFIX = "fragmentSuffix";
protected static final String TAG_ATTR_HOST = "host";
protected static final String TAG_ATTR_MANAGE_SPACE_ACTIVITY = "manageSpaceActivity";
protected static final String TAG_ATTR_MIMETYPE = "mimeType";
@@ -122,6 +128,11 @@
protected static final String TAG_ATTR_PERMISSION_GROUP = "permissionGroup";
protected static final String TAG_ATTR_PORT = "port";
protected static final String TAG_ATTR_PROCESS = "process";
+ protected static final String TAG_ATTR_QUERY = "query";
+ protected static final String TAG_ATTR_QUERY_ADVANCED_PATTERN = "queryAdvancedPattern";
+ protected static final String TAG_ATTR_QUERY_PATTERN = "queryPattern";
+ protected static final String TAG_ATTR_QUERY_PREFIX = "queryPrefix";
+ protected static final String TAG_ATTR_QUERY_SUFFIX = "querySuffix";
protected static final String TAG_ATTR_READ_PERMISSION = "readPermission";
protected static final String TAG_ATTR_REQUIRED_ACCOUNT_TYPE = "requiredAccountType";
protected static final String TAG_ATTR_REQUIRED_SYSTEM_PROPERTY_NAME =
@@ -143,7 +154,7 @@
// The length of mTagCounters corresponds to the number of tags defined in getCounterIdx. If new
// tags are added then the size here should be increased to match.
- private final TagCounter[] mTagCounters = new TagCounter[34];
+ private final TagCounter[] mTagCounters = new TagCounter[35];
String mTag;
@@ -238,9 +249,11 @@
return 31;
case TAG_INTENT:
return 32;
+ case TAG_URI_RELATIVE_FILTER_GROUP:
+ return 33;
default:
// The size of the mTagCounters array should be equal to this value+1
- return 33;
+ return 34;
}
}
@@ -276,6 +289,7 @@
case TAG_SERVICE:
case TAG_SUPPORTS_GL_TEXTURE:
case TAG_SUPPORTS_SCREENS:
+ case TAG_URI_RELATIVE_FILTER_GROUP:
case TAG_USES_CONFIGURATION:
case TAG_USES_FEATURE:
case TAG_USES_LIBRARY:
@@ -322,6 +336,7 @@
break;
case TAG_INTENT:
case TAG_INTENT_FILTER:
+ initializeCounter(TAG_URI_RELATIVE_FILTER_GROUP, 100);
initializeCounter(TAG_ACTION, 20000);
initializeCounter(TAG_CATEGORY, 40000);
initializeCounter(TAG_DATA, 40000);
@@ -354,6 +369,9 @@
initializeCounter(TAG_INTENT, 2000);
initializeCounter(TAG_PROVIDER, 8000);
break;
+ case TAG_URI_RELATIVE_FILTER_GROUP:
+ initializeCounter(TAG_DATA, 100);
+ break;
}
}
@@ -391,11 +409,21 @@
case TAG_ATTR_VERSION_NAME:
case TAG_ATTR_ZYGOTE_PRELOAD_NAME:
return MAX_ATTR_LEN_NAME;
+ case TAG_ATTR_FRAGMENT:
+ case TAG_ATTR_FRAGMENT_ADVANCED_PATTERN:
+ case TAG_ATTR_FRAGMENT_PATTERN:
+ case TAG_ATTR_FRAGMENT_PREFIX:
+ case TAG_ATTR_FRAGMENT_SUFFIX:
case TAG_ATTR_PATH:
case TAG_ATTR_PATH_ADVANCED_PATTERN:
case TAG_ATTR_PATH_PATTERN:
case TAG_ATTR_PATH_PREFIX:
case TAG_ATTR_PATH_SUFFIX:
+ case TAG_ATTR_QUERY:
+ case TAG_ATTR_QUERY_ADVANCED_PATTERN:
+ case TAG_ATTR_QUERY_PATTERN:
+ case TAG_ATTR_QUERY_PREFIX:
+ case TAG_ATTR_QUERY_SUFFIX:
return MAX_ATTR_LEN_PATH;
case TAG_ATTR_VALUE:
return MAX_ATTR_LEN_VALUE;
@@ -535,6 +563,16 @@
case R.styleable.AndroidManifestData_pathPrefix:
case R.styleable.AndroidManifestData_pathSuffix:
case R.styleable.AndroidManifestData_pathAdvancedPattern:
+ case R.styleable.AndroidManifestData_query:
+ case R.styleable.AndroidManifestData_queryPattern:
+ case R.styleable.AndroidManifestData_queryPrefix:
+ case R.styleable.AndroidManifestData_querySuffix:
+ case R.styleable.AndroidManifestData_queryAdvancedPattern:
+ case R.styleable.AndroidManifestData_fragment:
+ case R.styleable.AndroidManifestData_fragmentPattern:
+ case R.styleable.AndroidManifestData_fragmentPrefix:
+ case R.styleable.AndroidManifestData_fragmentSuffix:
+ case R.styleable.AndroidManifestData_fragmentAdvancedPattern:
return MAX_ATTR_LEN_PATH;
default:
return DEFAULT_MAX_STRING_ATTR_LENGTH;
diff --git a/core/java/android/credentials/GetCandidateCredentialsResponse.java b/core/java/android/credentials/GetCandidateCredentialsResponse.java
index 530fead..73361ad 100644
--- a/core/java/android/credentials/GetCandidateCredentialsResponse.java
+++ b/core/java/android/credentials/GetCandidateCredentialsResponse.java
@@ -19,7 +19,7 @@
import android.annotation.Hide;
import android.annotation.NonNull;
import android.app.PendingIntent;
-import android.credentials.ui.GetCredentialProviderData;
+import android.credentials.selection.GetCredentialProviderData;
import android.os.Parcel;
import android.os.Parcelable;
diff --git a/core/java/android/credentials/ui/AuthenticationEntry.java b/core/java/android/credentials/selection/AuthenticationEntry.java
similarity index 96%
rename from core/java/android/credentials/ui/AuthenticationEntry.java
rename to core/java/android/credentials/selection/AuthenticationEntry.java
index 9bd0871..54589e1 100644
--- a/core/java/android/credentials/ui/AuthenticationEntry.java
+++ b/core/java/android/credentials/selection/AuthenticationEntry.java
@@ -14,8 +14,11 @@
* limitations under the License.
*/
-package android.credentials.ui;
+package android.credentials.selection;
+import static android.credentials.flags.Flags.FLAG_CONFIGURABLE_SELECTOR_UI_ENABLED;
+
+import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -41,6 +44,7 @@
* @hide
*/
@TestApi
+@FlaggedApi(FLAG_CONFIGURABLE_SELECTOR_UI_ENABLED)
public final class AuthenticationEntry implements Parcelable {
@NonNull
private final String mKey;
diff --git a/core/java/android/credentials/ui/BaseDialogResult.java b/core/java/android/credentials/selection/BaseDialogResult.java
similarity index 81%
rename from core/java/android/credentials/ui/BaseDialogResult.java
rename to core/java/android/credentials/selection/BaseDialogResult.java
index e985a46..d4a73c3 100644
--- a/core/java/android/credentials/ui/BaseDialogResult.java
+++ b/core/java/android/credentials/selection/BaseDialogResult.java
@@ -14,11 +14,16 @@
* limitations under the License.
*/
-package android.credentials.ui;
+package android.credentials.selection;
+import static android.credentials.flags.Flags.FLAG_CONFIGURABLE_SELECTOR_UI_ENABLED;
+
+import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SuppressLint;
+import android.annotation.TestApi;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Parcel;
@@ -35,6 +40,10 @@
*
* @hide
*/
+@TestApi
+@FlaggedApi(FLAG_CONFIGURABLE_SELECTOR_UI_ENABLED)
+@SuppressLint("ParcelNotFinal") // Test API only. This is never intended to be officially exposed.
+// Instead proper final wrapper classes are defined (e.g. {@code FailureDialogResult}).
public class BaseDialogResult implements Parcelable {
/** Parses and returns a BaseDialogResult from the given resultData. */
@Nullable
@@ -54,7 +63,8 @@
* The intent extra key for the {@code BaseDialogResult} object when the credential
* selector activity finishes.
*/
- private static final String EXTRA_BASE_RESULT = "android.credentials.ui.extra.BASE_RESULT";
+ private static final String EXTRA_BASE_RESULT =
+ "android.credentials.selection.extra.BASE_RESULT";
/** @hide **/
@IntDef(prefix = {"RESULT_CODE_"}, value = {
@@ -92,13 +102,19 @@
mRequestToken = requestToken;
}
- /** Returns the unique identifier for the request that launched the operation. */
+ /**
+ * Returns the unique identifier for the request that launched the operation.
+ *
+ * @deprecated do not use
+ */
@Nullable
@Deprecated
public IBinder getRequestToken() {
return mRequestToken;
}
+ @SuppressLint("ParcelConstructor") // Test API only. This is never intended to be officially
+ // exposed. Instead proper final wrapper classes are defined (e.g. {@code FailureDialogResult}).
protected BaseDialogResult(@NonNull Parcel in) {
IBinder requestToken = in.readStrongBinder();
mRequestToken = requestToken;
diff --git a/core/java/android/credentials/ui/CancelUiRequest.java b/core/java/android/credentials/selection/CancelUiRequest.java
similarity index 96%
rename from core/java/android/credentials/ui/CancelUiRequest.java
rename to core/java/android/credentials/selection/CancelUiRequest.java
index 712424ce..fca0e2a 100644
--- a/core/java/android/credentials/ui/CancelUiRequest.java
+++ b/core/java/android/credentials/selection/CancelUiRequest.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.credentials.ui;
+package android.credentials.selection;
import android.annotation.NonNull;
import android.os.IBinder;
@@ -38,7 +38,7 @@
*/
@NonNull
public static final String EXTRA_CANCEL_UI_REQUEST =
- "android.credentials.ui.extra.CANCEL_UI_REQUEST";
+ "android.credentials.selection.extra.CANCEL_UI_REQUEST";
@NonNull
private final IBinder mToken;
diff --git a/core/java/android/credentials/ui/Constants.java b/core/java/android/credentials/selection/Constants.java
similarity index 86%
rename from core/java/android/credentials/ui/Constants.java
rename to core/java/android/credentials/selection/Constants.java
index 68f28e7..7e6c781 100644
--- a/core/java/android/credentials/ui/Constants.java
+++ b/core/java/android/credentials/selection/Constants.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.credentials.ui;
+package android.credentials.selection;
/**
* Constants for the ui protocol that doesn't fit into other individual data structures.
@@ -27,14 +27,14 @@
* The intent extra key for the {@code ResultReceiver} object when launching the UX activities.
*/
public static final String EXTRA_RESULT_RECEIVER =
- "android.credentials.ui.extra.RESULT_RECEIVER";
+ "android.credentials.selection.extra.RESULT_RECEIVER";
/**
* The intent extra key for indicating whether the bottom sheet should be started directly
* on the 'All Options' screen.
*/
public static final String EXTRA_REQ_FOR_ALL_OPTIONS =
- "android.credentials.ui.extra.REQ_FOR_ALL_OPTIONS";
+ "android.credentials.selection.extra.REQ_FOR_ALL_OPTIONS";
private Constants() {}
}
diff --git a/core/java/android/credentials/ui/CreateCredentialProviderData.java b/core/java/android/credentials/selection/CreateCredentialProviderData.java
similarity index 94%
rename from core/java/android/credentials/ui/CreateCredentialProviderData.java
rename to core/java/android/credentials/selection/CreateCredentialProviderData.java
index d7a4f5b..fc80ea8 100644
--- a/core/java/android/credentials/ui/CreateCredentialProviderData.java
+++ b/core/java/android/credentials/selection/CreateCredentialProviderData.java
@@ -14,8 +14,11 @@
* limitations under the License.
*/
-package android.credentials.ui;
+package android.credentials.selection;
+import static android.credentials.flags.Flags.FLAG_CONFIGURABLE_SELECTOR_UI_ENABLED;
+
+import android.annotation.FlaggedApi;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.TestApi;
@@ -33,6 +36,7 @@
* @hide
*/
@TestApi
+@FlaggedApi(FLAG_CONFIGURABLE_SELECTOR_UI_ENABLED)
public final class CreateCredentialProviderData extends ProviderData implements Parcelable {
@NonNull
private final List<Entry> mSaveEntries;
@@ -112,6 +116,7 @@
* @hide
*/
@TestApi
+ @FlaggedApi(FLAG_CONFIGURABLE_SELECTOR_UI_ENABLED)
public static final class Builder {
@NonNull private String mProviderFlattenedComponentName;
@NonNull private List<Entry> mSaveEntries = new ArrayList<>();
diff --git a/core/java/android/credentials/ui/CreateCredentialProviderInfo.java b/core/java/android/credentials/selection/CreateCredentialProviderInfo.java
similarity index 98%
rename from core/java/android/credentials/ui/CreateCredentialProviderInfo.java
rename to core/java/android/credentials/selection/CreateCredentialProviderInfo.java
index 41ca852..78b9fd44 100644
--- a/core/java/android/credentials/ui/CreateCredentialProviderInfo.java
+++ b/core/java/android/credentials/selection/CreateCredentialProviderInfo.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.credentials.ui;
+package android.credentials.selection;
import android.annotation.NonNull;
import android.annotation.Nullable;
diff --git a/core/java/android/credentials/ui/DisabledProviderData.java b/core/java/android/credentials/selection/DisabledProviderData.java
similarity index 90%
rename from core/java/android/credentials/ui/DisabledProviderData.java
rename to core/java/android/credentials/selection/DisabledProviderData.java
index 8bccdc9..b6f6ad4 100644
--- a/core/java/android/credentials/ui/DisabledProviderData.java
+++ b/core/java/android/credentials/selection/DisabledProviderData.java
@@ -14,8 +14,11 @@
* limitations under the License.
*/
-package android.credentials.ui;
+package android.credentials.selection;
+import static android.credentials.flags.Flags.FLAG_CONFIGURABLE_SELECTOR_UI_ENABLED;
+
+import android.annotation.FlaggedApi;
import android.annotation.NonNull;
import android.annotation.TestApi;
import android.os.Parcel;
@@ -27,6 +30,7 @@
* @hide
*/
@TestApi
+@FlaggedApi(FLAG_CONFIGURABLE_SELECTOR_UI_ENABLED)
public final class DisabledProviderData extends ProviderData implements Parcelable {
public DisabledProviderData(
diff --git a/core/java/android/credentials/ui/DisabledProviderInfo.java b/core/java/android/credentials/selection/DisabledProviderInfo.java
similarity index 97%
rename from core/java/android/credentials/ui/DisabledProviderInfo.java
rename to core/java/android/credentials/selection/DisabledProviderInfo.java
index 7ce6368..7d7dbc2 100644
--- a/core/java/android/credentials/ui/DisabledProviderInfo.java
+++ b/core/java/android/credentials/selection/DisabledProviderInfo.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.credentials.ui;
+package android.credentials.selection;
import android.annotation.NonNull;
diff --git a/core/java/android/credentials/ui/Entry.java b/core/java/android/credentials/selection/Entry.java
similarity index 95%
rename from core/java/android/credentials/ui/Entry.java
rename to core/java/android/credentials/selection/Entry.java
index 8469447..bcf4ee3 100644
--- a/core/java/android/credentials/ui/Entry.java
+++ b/core/java/android/credentials/selection/Entry.java
@@ -14,8 +14,11 @@
* limitations under the License.
*/
-package android.credentials.ui;
+package android.credentials.selection;
+import static android.credentials.flags.Flags.FLAG_CONFIGURABLE_SELECTOR_UI_ENABLED;
+
+import android.annotation.FlaggedApi;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SuppressLint;
@@ -34,6 +37,7 @@
* @hide
*/
@TestApi
+@FlaggedApi(FLAG_CONFIGURABLE_SELECTOR_UI_ENABLED)
public final class Entry implements Parcelable {
@NonNull
private final String mKey;
diff --git a/core/java/android/credentials/ui/FailureDialogResult.java b/core/java/android/credentials/selection/FailureDialogResult.java
similarity index 88%
rename from core/java/android/credentials/ui/FailureDialogResult.java
rename to core/java/android/credentials/selection/FailureDialogResult.java
index abd5a92..218aa46 100644
--- a/core/java/android/credentials/ui/FailureDialogResult.java
+++ b/core/java/android/credentials/selection/FailureDialogResult.java
@@ -14,10 +14,14 @@
* limitations under the License.
*/
-package android.credentials.ui;
+package android.credentials.selection;
+import static android.credentials.flags.Flags.FLAG_CONFIGURABLE_SELECTOR_UI_ENABLED;
+
+import android.annotation.FlaggedApi;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.TestApi;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Parcel;
@@ -28,6 +32,8 @@
*
* @hide
*/
+@TestApi
+@FlaggedApi(FLAG_CONFIGURABLE_SELECTOR_UI_ENABLED)
public final class FailureDialogResult extends BaseDialogResult implements Parcelable {
/** Parses and returns a UserSelectionDialogResult from the given resultData. */
@Nullable
@@ -50,7 +56,7 @@
* selector activity finishes.
*/
private static final String EXTRA_FAILURE_RESULT =
- "android.credentials.ui.extra.FAILURE_RESULT";
+ "android.credentials.selection.extra.FAILURE_RESULT";
@Nullable
private final String mErrorMessage;
@@ -66,7 +72,7 @@
return mErrorMessage;
}
- protected FailureDialogResult(@NonNull Parcel in) {
+ private FailureDialogResult(@NonNull Parcel in) {
super(in);
mErrorMessage = in.readString8();
}
diff --git a/core/java/android/credentials/ui/FailureResult.java b/core/java/android/credentials/selection/FailureResult.java
similarity index 90%
rename from core/java/android/credentials/ui/FailureResult.java
rename to core/java/android/credentials/selection/FailureResult.java
index ec58417..93ba671 100644
--- a/core/java/android/credentials/ui/FailureResult.java
+++ b/core/java/android/credentials/selection/FailureResult.java
@@ -14,11 +14,15 @@
* limitations under the License.
*/
-package android.credentials.ui;
+package android.credentials.selection;
+import static android.credentials.flags.Flags.FLAG_CONFIGURABLE_SELECTOR_UI_ENABLED;
+
+import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SystemApi;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -28,7 +32,9 @@
*
* @hide
*/
-public final class FailureResult implements UiResult {
+@SystemApi
+@FlaggedApi(FLAG_CONFIGURABLE_SELECTOR_UI_ENABLED)
+public final class FailureResult {
@Nullable
private final String mErrorMessage;
@NonNull
diff --git a/core/java/android/credentials/ui/GetCredentialProviderData.java b/core/java/android/credentials/selection/GetCredentialProviderData.java
similarity index 95%
rename from core/java/android/credentials/ui/GetCredentialProviderData.java
rename to core/java/android/credentials/selection/GetCredentialProviderData.java
index 481419b..2d09f60 100644
--- a/core/java/android/credentials/ui/GetCredentialProviderData.java
+++ b/core/java/android/credentials/selection/GetCredentialProviderData.java
@@ -14,8 +14,11 @@
* limitations under the License.
*/
-package android.credentials.ui;
+package android.credentials.selection;
+import static android.credentials.flags.Flags.FLAG_CONFIGURABLE_SELECTOR_UI_ENABLED;
+
+import android.annotation.FlaggedApi;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.TestApi;
@@ -33,6 +36,7 @@
* @hide
*/
@TestApi
+@FlaggedApi(FLAG_CONFIGURABLE_SELECTOR_UI_ENABLED)
public final class GetCredentialProviderData extends ProviderData implements Parcelable {
@NonNull
private final List<Entry> mCredentialEntries;
@@ -141,6 +145,7 @@
* @hide
*/
@TestApi
+ @FlaggedApi(FLAG_CONFIGURABLE_SELECTOR_UI_ENABLED)
public static final class Builder {
@NonNull
private String mProviderFlattenedComponentName;
diff --git a/core/java/android/credentials/ui/GetCredentialProviderInfo.java b/core/java/android/credentials/selection/GetCredentialProviderInfo.java
similarity index 99%
rename from core/java/android/credentials/ui/GetCredentialProviderInfo.java
rename to core/java/android/credentials/selection/GetCredentialProviderInfo.java
index bac7147..db0fb84 100644
--- a/core/java/android/credentials/ui/GetCredentialProviderInfo.java
+++ b/core/java/android/credentials/selection/GetCredentialProviderInfo.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.credentials.ui;
+package android.credentials.selection;
import android.annotation.NonNull;
import android.annotation.Nullable;
diff --git a/core/java/android/credentials/ui/IntentFactory.java b/core/java/android/credentials/selection/IntentFactory.java
similarity index 95%
rename from core/java/android/credentials/ui/IntentFactory.java
rename to core/java/android/credentials/selection/IntentFactory.java
index 5e1e0ef..c3a09ae 100644
--- a/core/java/android/credentials/ui/IntentFactory.java
+++ b/core/java/android/credentials/selection/IntentFactory.java
@@ -14,8 +14,11 @@
* limitations under the License.
*/
-package android.credentials.ui;
+package android.credentials.selection;
+import static android.credentials.flags.Flags.FLAG_CONFIGURABLE_SELECTOR_UI_ENABLED;
+
+import android.annotation.FlaggedApi;
import android.annotation.NonNull;
import android.annotation.SuppressLint;
import android.annotation.TestApi;
@@ -34,6 +37,7 @@
* @hide
*/
@TestApi
+@FlaggedApi(FLAG_CONFIGURABLE_SELECTOR_UI_ENABLED)
public class IntentFactory {
/**
diff --git a/core/java/android/credentials/ui/IntentHelper.java b/core/java/android/credentials/selection/IntentHelper.java
similarity index 98%
rename from core/java/android/credentials/ui/IntentHelper.java
rename to core/java/android/credentials/selection/IntentHelper.java
index c5f34c1..6bcd05a 100644
--- a/core/java/android/credentials/ui/IntentHelper.java
+++ b/core/java/android/credentials/selection/IntentHelper.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.credentials.ui;
+package android.credentials.selection;
import android.annotation.NonNull;
import android.annotation.Nullable;
diff --git a/core/java/android/credentials/ui/ProviderData.java b/core/java/android/credentials/selection/ProviderData.java
similarity index 81%
rename from core/java/android/credentials/ui/ProviderData.java
rename to core/java/android/credentials/selection/ProviderData.java
index 1e5aa24..e7a7d77 100644
--- a/core/java/android/credentials/ui/ProviderData.java
+++ b/core/java/android/credentials/selection/ProviderData.java
@@ -14,8 +14,11 @@
* limitations under the License.
*/
-package android.credentials.ui;
+package android.credentials.selection;
+import static android.credentials.flags.Flags.FLAG_CONFIGURABLE_SELECTOR_UI_ENABLED;
+
+import android.annotation.FlaggedApi;
import android.annotation.NonNull;
import android.annotation.SuppressLint;
import android.annotation.TestApi;
@@ -30,6 +33,7 @@
* @hide
*/
@TestApi
+@FlaggedApi(FLAG_CONFIGURABLE_SELECTOR_UI_ENABLED)
@SuppressLint({"ParcelCreator", "ParcelNotFinal"})
public abstract class ProviderData implements Parcelable {
@@ -38,13 +42,13 @@
* launching the UX activities.
*/
public static final String EXTRA_ENABLED_PROVIDER_DATA_LIST =
- "android.credentials.ui.extra.ENABLED_PROVIDER_DATA_LIST";
+ "android.credentials.selection.extra.ENABLED_PROVIDER_DATA_LIST";
/**
* The intent extra key for the list of {@code ProviderData} from disabled providers when
* launching the UX activities.
*/
public static final String EXTRA_DISABLED_PROVIDER_DATA_LIST =
- "android.credentials.ui.extra.DISABLED_PROVIDER_DATA_LIST";
+ "android.credentials.selection.extra.DISABLED_PROVIDER_DATA_LIST";
@NonNull
private final String mProviderFlattenedComponentName;
@@ -63,6 +67,9 @@
return mProviderFlattenedComponentName;
}
+ @SuppressLint("ParcelConstructor") // Test API only. This is never intended to be officially
+ // exposed. Instead proper final wrapper classes are defined (e.g.
+ // {@code GetCredentialProviderInfo}).
protected ProviderData(@NonNull Parcel in) {
String providerFlattenedComponentName = in.readString8();
mProviderFlattenedComponentName = providerFlattenedComponentName;
diff --git a/core/java/android/credentials/selection/ProviderPendingIntentResponse.java b/core/java/android/credentials/selection/ProviderPendingIntentResponse.java
new file mode 100644
index 0000000..281f34a
--- /dev/null
+++ b/core/java/android/credentials/selection/ProviderPendingIntentResponse.java
@@ -0,0 +1,124 @@
+/*
+ * 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.credentials.selection;
+
+import static android.credentials.flags.Flags.FLAG_CONFIGURABLE_SELECTOR_UI_ENABLED;
+
+import android.annotation.FlaggedApi;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SuppressLint;
+import android.annotation.SystemApi;
+import android.content.Intent;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.ResultReceiver;
+
+/**
+ * Result of launching a provider's PendingIntent associated with an {@link Entry} after it is
+ * selected by the user.
+ *
+ * The provider sets the credential creation / retrieval result through
+ * {@link android.app.Activity#setResult(int, Intent)}, which is then directly propagated back
+ * through this data structure.
+ *
+ * @hide
+ */
+@SystemApi
+@FlaggedApi(FLAG_CONFIGURABLE_SELECTOR_UI_ENABLED)
+public final class ProviderPendingIntentResponse implements Parcelable {
+ private final int mResultCode;
+ @Nullable
+ private final Intent mResultData;
+
+ /**
+ * Constructs a {@link ProviderPendingIntentResponse}.
+ *
+ * When a user makes a selection, you should launch the associated provider PendingIntent,
+ * and expect the provider activity to complete and set
+ * {@link android.app.Activity#setResult(int, Intent)}. You should then immediately pass back
+ * the provider activity result code and data to the system service using this data class,
+ * via the {@link ResultHelper#sendUserSelectionResult(ResultReceiver, UserSelectionResult)}
+ * API.
+ *
+ * @param resultCode the resultCode returned from the provider activity
+ * @param resultData the result data returned from the provider activity; only set to null if
+ * the provider result (a provider would set it via
+ * {@link android.app.Activity#setResult(int, Intent)}) your UI received
+ * was actually null
+ */
+ public ProviderPendingIntentResponse(int resultCode, @Nullable Intent resultData) {
+ mResultCode = resultCode;
+ mResultData = resultData;
+ }
+
+ private ProviderPendingIntentResponse(@NonNull Parcel in) {
+ mResultCode = in.readInt();
+ mResultData = in.readTypedObject(Intent.CREATOR);
+ }
+
+ public static final @NonNull Creator<ProviderPendingIntentResponse> CREATOR =
+ new Creator<>() {
+ @Override
+ public ProviderPendingIntentResponse createFromParcel(@NonNull Parcel in) {
+ return new ProviderPendingIntentResponse(in);
+ }
+
+ @Override
+ public ProviderPendingIntentResponse[] newArray(int size) {
+ return new ProviderPendingIntentResponse[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeInt(mResultCode);
+ dest.writeTypedObject(mResultData, flags);
+ }
+
+ /**
+ * Returns the result code associated with this provider PendingIntent activity result, i.e.
+ * the {@code resultCode} that the provider activity has set using the
+ * {@link android.app.Activity#setResult(int, Intent)} API.
+ */
+ public int getResultCode() {
+ return mResultCode;
+ }
+
+ /**
+ * Returns the result data associated with this provider PendingIntent activity result, i.e.
+ * the {@code data} that the provider activity has set using the
+ * {@link android.app.Activity#setResult(int, Intent)} API.
+ *
+ * Notice that this value can be null if the provider UI result (a provider would set it via
+ * {@link android.app.Activity#setResult(int, Intent)}) that your UI received was actually null,
+ * which indicates an implementation error on the provider side. The system service will
+ * gracefully handle this by passing back an API exception (
+ * {@link android.credentials.GetCredentialException} or
+ * {@link android.credentials.CreateCredentialException}).
+ */
+ @SuppressLint("IntentBuilderName") // Not building a new intent.
+ @Nullable
+ public Intent getResultData() {
+ return mResultData;
+ }
+}
diff --git a/core/java/android/credentials/ui/RequestInfo.java b/core/java/android/credentials/selection/RequestInfo.java
similarity index 82%
rename from core/java/android/credentials/ui/RequestInfo.java
rename to core/java/android/credentials/selection/RequestInfo.java
index f651584..7d6ea7e 100644
--- a/core/java/android/credentials/ui/RequestInfo.java
+++ b/core/java/android/credentials/selection/RequestInfo.java
@@ -14,8 +14,11 @@
* limitations under the License.
*/
-package android.credentials.ui;
+package android.credentials.selection;
+import static android.credentials.flags.Flags.FLAG_CONFIGURABLE_SELECTOR_UI_ENABLED;
+
+import android.annotation.FlaggedApi;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.StringDef;
@@ -39,39 +42,46 @@
* @hide
*/
@TestApi
+@FlaggedApi(FLAG_CONFIGURABLE_SELECTOR_UI_ENABLED)
public final class RequestInfo implements Parcelable {
/**
* The intent extra key for the {@code RequestInfo} object when launching the UX
* activities.
*/
- @NonNull public static final String EXTRA_REQUEST_INFO =
- "android.credentials.ui.extra.REQUEST_INFO";
+ @NonNull
+ public static final String EXTRA_REQUEST_INFO =
+ "android.credentials.selection.extra.REQUEST_INFO";
/**
* Type value for any request that does not require UI.
*/
- @NonNull public static final String TYPE_UNDEFINED = "android.credentials.ui.TYPE_UNDEFINED";
+ @NonNull
+ public static final String TYPE_UNDEFINED = "android.credentials.selection.TYPE_UNDEFINED";
/**
* Type value for a getCredential request.
*/
- @NonNull public static final String TYPE_GET = "android.credentials.ui.TYPE_GET";
+ @NonNull
+ public static final String TYPE_GET = "android.credentials.selection.TYPE_GET";
/**
* Type value for a getCredential request that utilizes the credential registry.
*
* @hide
*/
- @NonNull public static final String TYPE_GET_VIA_REGISTRY =
- "android.credentials.ui.TYPE_GET_VIA_REGISTRY";
+ @NonNull
+ public static final String TYPE_GET_VIA_REGISTRY =
+ "android.credentials.selection.TYPE_GET_VIA_REGISTRY";
/**
* Type value for a createCredential request.
*/
- @NonNull public static final String TYPE_CREATE = "android.credentials.ui.TYPE_CREATE";
+ @NonNull
+ public static final String TYPE_CREATE = "android.credentials.selection.TYPE_CREATE";
/** @hide */
@Retention(RetentionPolicy.SOURCE)
- @StringDef(value = { TYPE_GET, TYPE_CREATE })
- public @interface RequestType {}
+ @StringDef(value = {TYPE_GET, TYPE_CREATE})
+ public @interface RequestType {
+ }
@NonNull
private final IBinder mToken;
@@ -82,6 +92,9 @@
@NonNull
private final List<String> mDefaultProviderIds;
+ @NonNull
+ private final List<String> mRegistryProviderIds;
+
@Nullable
private final GetCredentialRequest mGetCredentialRequest;
@@ -105,11 +118,7 @@
/*defaultProviderIds=*/ new ArrayList<>());
}
- /**
- * Creates new {@code RequestInfo} for a create-credential flow.
- *
- * @hide
- */
+ /** Creates new {@code RequestInfo} for a create-credential flow. */
@NonNull
public static RequestInfo newCreateRequestInfo(
@NonNull IBinder token, @NonNull CreateCredentialRequest createCredentialRequest,
@@ -120,11 +129,7 @@
hasPermissionToOverrideDefault, defaultProviderIds);
}
- /**
- * Creates new {@code RequestInfo} for a get-credential flow.
- *
- * @hide
- */
+ /** Creates new {@code RequestInfo} for a get-credential flow. */
@NonNull
public static RequestInfo newGetRequestInfo(
@NonNull IBinder token, @NonNull GetCredentialRequest getCredentialRequest,
@@ -147,11 +152,7 @@
}
- /**
- * Returns whether the calling package has the permission
- *
- * @hide
- */
+ /** Returns whether the calling package has the permission. */
public boolean hasPermissionToOverrideDefault() {
return mHasPermissionToOverrideDefault;
}
@@ -185,13 +186,11 @@
}
/**
- * Returns default provider identifier (flattened component name) configured from the user
+ * Returns default provider identifiers (component or package name) configured from the user
* settings.
*
* Will only be possibly non-empty for the create use case. Not meaningful for the sign-in use
* case.
- *
- * @hide
*/
@NonNull
public List<String> getDefaultProviderIds() {
@@ -199,6 +198,15 @@
}
/**
+ * Returns provider identifiers (component or package name) that have been validated to provide
+ * registry entries.
+ */
+ @NonNull
+ public List<String> getRegistryProviderIds() {
+ return mRegistryProviderIds;
+ }
+
+ /**
* Returns the non-null GetCredentialRequest when the type of the request is {@link
* #TYPE_GET}, or null otherwise.
*/
@@ -220,6 +228,7 @@
mGetCredentialRequest = getCredentialRequest;
mHasPermissionToOverrideDefault = hasPermissionToOverrideDefault;
mDefaultProviderIds = defaultProviderIds == null ? new ArrayList<>() : defaultProviderIds;
+ mRegistryProviderIds = new ArrayList<>();
}
private RequestInfo(@NonNull Parcel in) {
@@ -241,6 +250,7 @@
mGetCredentialRequest = getCredentialRequest;
mHasPermissionToOverrideDefault = in.readBoolean();
mDefaultProviderIds = in.createStringArrayList();
+ mRegistryProviderIds = in.createStringArrayList();
}
@Override
@@ -252,6 +262,7 @@
dest.writeTypedObject(mGetCredentialRequest, flags);
dest.writeBoolean(mHasPermissionToOverrideDefault);
dest.writeStringList(mDefaultProviderIds);
+ dest.writeStringList(mRegistryProviderIds);
}
@Override
@@ -259,7 +270,8 @@
return 0;
}
- @NonNull public static final Creator<RequestInfo> CREATOR = new Creator<>() {
+ @NonNull
+ public static final Creator<RequestInfo> CREATOR = new Creator<>() {
@Override
public RequestInfo createFromParcel(@NonNull Parcel in) {
return new RequestInfo(in);
diff --git a/core/java/android/credentials/ui/ResultHelper.java b/core/java/android/credentials/selection/ResultHelper.java
similarity index 73%
rename from core/java/android/credentials/ui/ResultHelper.java
rename to core/java/android/credentials/selection/ResultHelper.java
index 7b9d5e8..d6347b0 100644
--- a/core/java/android/credentials/ui/ResultHelper.java
+++ b/core/java/android/credentials/selection/ResultHelper.java
@@ -14,9 +14,13 @@
* limitations under the License.
*/
-package android.credentials.ui;
+package android.credentials.selection;
+import static android.credentials.flags.Flags.FLAG_CONFIGURABLE_SELECTOR_UI_ENABLED;
+
+import android.annotation.FlaggedApi;
import android.annotation.NonNull;
+import android.annotation.SystemApi;
import android.content.Intent;
import android.os.Bundle;
import android.os.ResultReceiver;
@@ -26,13 +30,16 @@
*
* @hide
*/
+@SystemApi
+@FlaggedApi(FLAG_CONFIGURABLE_SELECTOR_UI_ENABLED)
public final class ResultHelper {
/**
* Sends the {@code failureResult} that caused the UI to stop back to the CredentialManager
* service.
*
- * The {code resultReceiver} for a UI flow can be extracted from the UI launch intent via
- * {@link IntentHelper#extractResultReceiver(Intent)}.
+ * @param resultReceiver the ResultReceiver sent from the system service, that can be extracted
+ * from the launch intent via
+ * {@link IntentHelper#extractResultReceiver(Intent)}
*/
public static void sendFailureResult(@NonNull ResultReceiver resultReceiver,
@NonNull FailureResult failureResult) {
@@ -46,8 +53,9 @@
/**
* Sends the completed {@code userSelectionResult} back to the CredentialManager service.
*
- * The {code resultReceiver} for a UI flow can be extracted from the UI launch intent via
- * {@link IntentHelper#extractResultReceiver(Intent)}.
+ * @param resultReceiver the ResultReceiver sent from the system service, that can be extracted
+ * from the launch intent via
+ * {@link IntentHelper#extractResultReceiver(Intent)}
*/
public static void sendUserSelectionResult(@NonNull ResultReceiver resultReceiver,
@NonNull UserSelectionResult userSelectionResult) {
diff --git a/core/java/android/credentials/ui/UserSelectionDialogResult.java b/core/java/android/credentials/selection/UserSelectionDialogResult.java
similarity index 79%
rename from core/java/android/credentials/ui/UserSelectionDialogResult.java
rename to core/java/android/credentials/selection/UserSelectionDialogResult.java
index 3089bf6..50d5aa3 100644
--- a/core/java/android/credentials/ui/UserSelectionDialogResult.java
+++ b/core/java/android/credentials/selection/UserSelectionDialogResult.java
@@ -14,10 +14,14 @@
* limitations under the License.
*/
-package android.credentials.ui;
+package android.credentials.selection;
+import static android.credentials.flags.Flags.FLAG_CONFIGURABLE_SELECTOR_UI_ENABLED;
+
+import android.annotation.FlaggedApi;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.TestApi;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Parcel;
@@ -30,17 +34,19 @@
*
* @hide
*/
+@TestApi
+@FlaggedApi(FLAG_CONFIGURABLE_SELECTOR_UI_ENABLED)
public final class UserSelectionDialogResult extends BaseDialogResult implements Parcelable {
/** Parses and returns a UserSelectionDialogResult from the given resultData. */
@Nullable
public static UserSelectionDialogResult fromResultData(@NonNull Bundle resultData) {
return resultData.getParcelable(
- EXTRA_USER_SELECTION_RESULT, UserSelectionDialogResult.class);
+ EXTRA_USER_SELECTION_RESULT, UserSelectionDialogResult.class);
}
/**
* Used for the UX to construct the {@code resultData Bundle} to send via the {@code
- * ResultReceiver}.
+ * ResultReceiver}.
*/
public static void addToBundle(
@NonNull UserSelectionDialogResult result, @NonNull Bundle bundle) {
@@ -52,12 +58,16 @@
* selector activity finishes.
*/
private static final String EXTRA_USER_SELECTION_RESULT =
- "android.credentials.ui.extra.USER_SELECTION_RESULT";
+ "android.credentials.selection.extra.USER_SELECTION_RESULT";
- @NonNull private final String mProviderId;
- @NonNull private final String mEntryKey;
- @NonNull private final String mEntrySubkey;
- @Nullable private ProviderPendingIntentResponse mProviderPendingIntentResponse;
+ @NonNull
+ private final String mProviderId;
+ @NonNull
+ private final String mEntryKey;
+ @NonNull
+ private final String mEntrySubkey;
+ @Nullable
+ private ProviderPendingIntentResponse mProviderPendingIntentResponse;
public UserSelectionDialogResult(
@Nullable IBinder requestToken, @NonNull String providerId,
@@ -103,7 +113,7 @@
return mProviderPendingIntentResponse;
}
- protected UserSelectionDialogResult(@NonNull Parcel in) {
+ private UserSelectionDialogResult(@NonNull Parcel in) {
super(in);
String providerId = in.readString8();
String entryKey = in.readString8();
@@ -134,14 +144,14 @@
public static final @NonNull Creator<UserSelectionDialogResult> CREATOR =
new Creator<UserSelectionDialogResult>() {
- @Override
- public UserSelectionDialogResult createFromParcel(@NonNull Parcel in) {
- return new UserSelectionDialogResult(in);
- }
+ @Override
+ public UserSelectionDialogResult createFromParcel(@NonNull Parcel in) {
+ return new UserSelectionDialogResult(in);
+ }
- @Override
- public UserSelectionDialogResult[] newArray(int size) {
- return new UserSelectionDialogResult[size];
- }
- };
+ @Override
+ public UserSelectionDialogResult[] newArray(int size) {
+ return new UserSelectionDialogResult[size];
+ }
+ };
}
diff --git a/core/java/android/credentials/selection/UserSelectionResult.java b/core/java/android/credentials/selection/UserSelectionResult.java
new file mode 100644
index 0000000..235a5d5
--- /dev/null
+++ b/core/java/android/credentials/selection/UserSelectionResult.java
@@ -0,0 +1,105 @@
+/*
+ * 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.
+ */
+
+package android.credentials.selection;
+
+import static android.credentials.flags.Flags.FLAG_CONFIGURABLE_SELECTOR_UI_ENABLED;
+
+import android.annotation.FlaggedApi;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+
+import com.android.internal.util.Preconditions;
+
+/**
+ * Result sent back from the UI after the user chose an option and completed the following
+ * transaction launched through the provider PendingIntent associated with that option.
+ *
+ * @hide
+ */
+@SystemApi
+@FlaggedApi(FLAG_CONFIGURABLE_SELECTOR_UI_ENABLED)
+public final class UserSelectionResult {
+ @NonNull
+ private final String mProviderId;
+ @NonNull
+ private final String mEntryKey;
+ @NonNull
+ private final String mEntrySubkey;
+ @Nullable
+ private ProviderPendingIntentResponse mProviderPendingIntentResponse;
+
+ /**
+ * Constructs a {@link UserSelectionResult}.
+ *
+ * @param providerId the provider identifier (component name or package name) whose entry was
+ * selected by the user; the value should map to the
+ * {@link GetCredentialProviderInfo#getProviderName()} that provided this entry
+ * @param entryKey the identifier of this selected entry, i.e. the selected entry's
+ * {@link Entry#getKey()}
+ * @param entrySubkey the sub-identifier of this selected entry, i.e. the selected entry's
+ * {@link Entry#getSubkey()}
+ * @param providerPendingIntentResponse the provider activity result of launching the provider
+ * PendingIntent associated with this selection; or null
+ * if the associated selection didn't have an associated
+ * provider PendingIntent
+ * @throws IllegalArgumentException if {@code providerId}, {@code entryKey}, or
+ * {@code entrySubkey} is empty
+ */
+
+ public UserSelectionResult(@NonNull String providerId,
+ @NonNull String entryKey, @NonNull String entrySubkey,
+ @Nullable ProviderPendingIntentResponse providerPendingIntentResponse) {
+ mProviderId = Preconditions.checkStringNotEmpty(providerId);
+ mEntryKey = Preconditions.checkStringNotEmpty(entryKey);
+ mEntrySubkey = Preconditions.checkStringNotEmpty(entrySubkey);
+ mProviderPendingIntentResponse = providerPendingIntentResponse;
+ }
+
+ /**
+ * Returns the provider identifier (component name or package name) whose entry was selected by
+ * the user.
+ */
+ @NonNull
+ public String getProviderId() {
+ return mProviderId;
+ }
+
+ /** Returns the identifier of the visual entry that the user selected. */
+ @NonNull
+ public String getEntryKey() {
+ return mEntryKey;
+ }
+
+ /** Returns the sub-identifier of the visual entry that the user selected. */
+ @NonNull
+ public String getEntrySubkey() {
+ return mEntrySubkey;
+ }
+
+ /** Returns the pending intent response from the provider. */
+ @Nullable
+ public ProviderPendingIntentResponse getPendingIntentProviderResponse() {
+ return mProviderPendingIntentResponse;
+ }
+
+ @NonNull
+ UserSelectionDialogResult toUserSelectionDialogResult() {
+ return new UserSelectionDialogResult(/*requestToken=*/null, mProviderId, mEntryKey,
+ mEntrySubkey, mProviderPendingIntentResponse);
+ }
+}
diff --git a/core/java/android/credentials/ui/ProviderPendingIntentResponse.java b/core/java/android/credentials/ui/ProviderPendingIntentResponse.java
deleted file mode 100644
index 11cc21f9..0000000
--- a/core/java/android/credentials/ui/ProviderPendingIntentResponse.java
+++ /dev/null
@@ -1,87 +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.credentials.ui;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.SuppressLint;
-import android.content.Intent;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * Result of launching a provider's PendingIntent associated with an {@link Entry} after it is
- * selected by the user.
- *
- * The provider sets the credential creation / retrieval result through
- * {@link android.app.Activity#setResult(int, Intent)}, which is then directly propagated back
- * through this data structure.
- *
- * @hide
- */
-public final class ProviderPendingIntentResponse implements Parcelable {
- private final int mResultCode;
- @Nullable
- private final Intent mResultData;
-
- /** Constructs a {@link ProviderPendingIntentResponse}. */
- public ProviderPendingIntentResponse(int resultCode, @Nullable Intent resultData) {
- mResultCode = resultCode;
- mResultData = resultData;
- }
-
- private ProviderPendingIntentResponse(@NonNull Parcel in) {
- mResultCode = in.readInt();
- mResultData = in.readTypedObject(Intent.CREATOR);
- }
-
- public static final @NonNull Creator<ProviderPendingIntentResponse> CREATOR =
- new Creator<>() {
- @Override
- public ProviderPendingIntentResponse createFromParcel(@NonNull Parcel in) {
- return new ProviderPendingIntentResponse(in);
- }
-
- @Override
- public ProviderPendingIntentResponse[] newArray(int size) {
- return new ProviderPendingIntentResponse[size];
- }
- };
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(@NonNull Parcel dest, int flags) {
- dest.writeInt(mResultCode);
- dest.writeTypedObject(mResultData, flags);
- }
-
- /** Returns the result code associated with this provider PendingIntent activity result. */
- public int getResultCode() {
- return mResultCode;
- }
-
- /** Returns the result data associated with this provider PendingIntent activity result. */
- @SuppressLint("IntentBuilderName") // Not building a new intent.
- @NonNull
- public Intent getResultData() {
- return mResultData;
- }
-}
diff --git a/core/java/android/credentials/ui/UserSelectionResult.java b/core/java/android/credentials/ui/UserSelectionResult.java
deleted file mode 100644
index 431dc63..0000000
--- a/core/java/android/credentials/ui/UserSelectionResult.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * 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.
- */
-
-package android.credentials.ui;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-
-import com.android.internal.util.Preconditions;
-
-/**
- * Result sent back from the UI after the user chose an option and completed the following
- * transaction launched through the provider PendingIntent associated with that option.
- *
- * @hide
- */
-public final class UserSelectionResult implements UiResult {
- @NonNull
- private final String mProviderId;
- @NonNull
- private final String mEntryKey;
- @NonNull
- private final String mEntrySubkey;
- @Nullable
- private ProviderPendingIntentResponse mProviderPendingIntentResponse;
-
- /**
- * Constructs a {@link UserSelectionResult}.
- *
- * @throws IllegalArgumentException if {@code providerId} is empty
- */
-
- public UserSelectionResult(@NonNull String providerId,
- @NonNull String entryKey, @NonNull String entrySubkey,
- @Nullable ProviderPendingIntentResponse providerPendingIntentResponse) {
- mProviderId = Preconditions.checkStringNotEmpty(providerId);
- mEntryKey = Preconditions.checkNotNull(entryKey);
- mEntrySubkey = Preconditions.checkNotNull(entrySubkey);
- mProviderPendingIntentResponse = providerPendingIntentResponse;
- }
-
- /** Returns provider package name whose entry was selected by the user. */
- @NonNull
- public String getProviderId() {
- return mProviderId;
- }
-
- /** Returns the key of the visual entry that the user selected. */
- @NonNull
- public String getEntryKey() {
- return mEntryKey;
- }
-
- /** Returns the subkey of the visual entry that the user selected. */
- @NonNull
- public String getEntrySubkey() {
- return mEntrySubkey;
- }
-
- /** Returns the pending intent response from the provider. */
- @Nullable
- public ProviderPendingIntentResponse getPendingIntentProviderResponse() {
- return mProviderPendingIntentResponse;
- }
-
- @NonNull
- UserSelectionDialogResult toUserSelectionDialogResult() {
- return new UserSelectionDialogResult(/*requestToken=*/null, mProviderId, mEntryKey,
- mEntrySubkey, mProviderPendingIntentResponse);
- }
-}
diff --git a/core/java/android/hardware/camera2/extension/CameraOutputConfig.aidl b/core/java/android/hardware/camera2/extension/CameraOutputConfig.aidl
index 7c54a9b..509bcb8 100644
--- a/core/java/android/hardware/camera2/extension/CameraOutputConfig.aidl
+++ b/core/java/android/hardware/camera2/extension/CameraOutputConfig.aidl
@@ -26,6 +26,7 @@
Surface surface;
int imageFormat;
int capacity;
+ long usage;
const int TYPE_SURFACE = 0;
const int TYPE_IMAGEREADER = 1;
diff --git a/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
index 98bc311..f6c8f36 100644
--- a/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
@@ -1182,7 +1182,8 @@
return null;
}
ImageReader reader = ImageReader.newInstance(output.size.width,
- output.size.height, output.imageFormat, output.capacity);
+ output.size.height, output.imageFormat, output.capacity,
+ output.usage);
mReaderMap.put(output.outputId.id, reader);
return reader.getSurface();
case CameraOutputConfig.TYPE_MULTIRES_IMAGEREADER:
diff --git a/core/java/android/os/PatternMatcher.java b/core/java/android/os/PatternMatcher.java
index b5425b4..79a2c59 100644
--- a/core/java/android/os/PatternMatcher.java
+++ b/core/java/android/os/PatternMatcher.java
@@ -16,9 +16,12 @@
package android.os;
+import android.annotation.IntDef;
import android.util.Log;
import android.util.proto.ProtoOutputStream;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.Arrays;
/**
@@ -68,6 +71,17 @@
*/
public static final int PATTERN_SUFFIX = 4;
+ /** @hide */
+ @IntDef(value = {
+ PATTERN_LITERAL,
+ PATTERN_PREFIX,
+ PATTERN_SIMPLE_GLOB,
+ PATTERN_ADVANCED_GLOB,
+ PATTERN_SUFFIX,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface PatternType {}
+
// token types for advanced matching
private static final int TOKEN_TYPE_LITERAL = 0;
private static final int TOKEN_TYPE_ANY = 1;
diff --git a/core/java/android/os/TestLooperManager.java b/core/java/android/os/TestLooperManager.java
index 5e7549f..4b16c1d 100644
--- a/core/java/android/os/TestLooperManager.java
+++ b/core/java/android/os/TestLooperManager.java
@@ -28,6 +28,7 @@
* The test code may use {@link #next()} to acquire messages that have been queued to this
* {@link Looper}/{@link MessageQueue} and then {@link #execute} to run any that desires.
*/
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
public class TestLooperManager {
private static final ArraySet<Looper> sHeldLoopers = new ArraySet<>();
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 533946d..d6df8d9 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -1898,6 +1898,30 @@
"no_near_field_communication_radio";
/**
+ * This user restriction specifies if Thread network is disallowed on the device. If Thread
+ * network is disallowed it cannot be turned on via Settings.
+ *
+ * <p>This restriction can only be set by a device owner or a profile owner of an
+ * organization-owned managed profile on the parent profile.
+ * In both cases, the restriction applies globally on the device and will turn off the
+ * Thread network radio if it's currently on and prevent the radio from being turned
+ * on in the future.
+ *
+ * <p> <a href="https://www.threadgroup.org">Thread</a> is a low-power and low-latency wireless
+ * mesh networking protocol built on IPv6.
+ *
+ * <p>Default is <code>false</code>.
+ *
+ * <p>Key for user restrictions.
+ * <p>Type: Boolean
+ * @see DevicePolicyManager#addUserRestriction(ComponentName, String)
+ * @see DevicePolicyManager#clearUserRestriction(ComponentName, String)
+ * @see #getUserRestrictions()
+ */
+ @FlaggedApi("com.android.net.thread.flags.thread_user_restriction_enabled")
+ public static final String DISALLOW_THREAD_NETWORK = "no_thread_network";
+
+ /**
* List of key values that can be passed into the various user restriction related methods
* in {@link UserManager} & {@link DevicePolicyManager}.
* Note: This is slightly different from the real set of user restrictions listed in {@link
@@ -1983,6 +2007,7 @@
DISALLOW_ULTRA_WIDEBAND_RADIO,
DISALLOW_GRANT_ADMIN,
DISALLOW_NEAR_FIELD_COMMUNICATION_RADIO,
+ DISALLOW_THREAD_NETWORK,
})
@Retention(RetentionPolicy.SOURCE)
public @interface UserRestrictionKey {}
diff --git a/core/java/android/provider/ContactKeysManager.java b/core/java/android/provider/ContactKeysManager.java
new file mode 100644
index 0000000..ecde699
--- /dev/null
+++ b/core/java/android/provider/ContactKeysManager.java
@@ -0,0 +1,1129 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.provider;
+
+import android.annotation.FlaggedApi;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
+import android.content.ContentProviderClient;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.RemoteException;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * ContactKeysManager provides the access to the E2EE contact keys provider.
+ * It manages two types of keys - {@link ContactKey} of other users' and the owner's keys -
+ * {@link SelfKey}.
+ * <ul>
+ * <li>
+ * For {@link ContactKey} this API allows the insert/update, removal, changing of the
+ * verification state, retrieving the keys (either created by or visible to the caller app)
+ * operations.
+ * </li>
+ * <li>
+ * For {@link SelfKey} this API allows the insert/update, removal, retrieving the self keys
+ * (either created by or visible to the caller app) operations.
+ * </li>
+ * </ul>
+ * Keys are uniquely identified by:
+ * <ul>
+ * <li>
+ * ownerPackageName - package name of an app that the key belongs to.
+ * </li>
+ * <li>
+ * deviceId - an app-specified identifier for the device, defined by the app. Within that app,
+ * the deviceID should be unique among devices belonging to that user.
+ * </li>
+ * <li>
+ * accountId - the app-specified identifier for the account for which the contact key can be used.
+ * Usually a phone number.
+ * </li>
+ * </ul>
+ * Contact keys also use lookupKey which is an opaque value used to identify a contact in
+ * ContactsProvider.
+ */
+@FlaggedApi(Flags.FLAG_USER_KEYS)
+public class ContactKeysManager {
+ /**
+ * The authority for the contact keys provider.
+ * @hide
+ */
+ public static final String AUTHORITY = "com.android.contactkeys.contactkeysprovider";
+
+ /**
+ * A content:// style uri to the authority for the contact keys provider.
+ * @hide
+ */
+ @NonNull
+ public static final Uri AUTHORITY_URI = Uri.parse("content://" + AUTHORITY);
+
+ /**
+ * Maximum size of a contact key.
+ */
+ private static final int MAX_KEY_SIZE_BYTES = 5000;
+
+ /**
+ * Special value to distinguish a null array in a parcelable object.
+ */
+ private static final int ARRAY_IS_NULL = -1;
+
+ @NonNull
+ private final ContentResolver mContentResolver;
+
+ /** @hide */
+ public ContactKeysManager(@NonNull Context context) {
+ Objects.requireNonNull(context);
+ mContentResolver = context.getContentResolver();
+ }
+
+ /**
+ * Inserts a new entry into the contact keys table or updates one if it already exists.
+ * The inserted/updated contact key is owned by the caller app.
+ *
+ * @param lookupKey value that references the contact
+ * @param deviceId an app-specified identifier for the device
+ * @param accountId an app-specified identifier for the account
+ * @param keyValue the raw bytes for the key (max size is {@link #getMaxKeySizeBytes} bytes)
+ */
+ @RequiresPermission(android.Manifest.permission.WRITE_CONTACTS)
+ public void updateOrInsertContactKey(@NonNull String lookupKey,
+ @NonNull String deviceId,
+ @NonNull String accountId,
+ @NonNull byte[] keyValue) {
+ validateKeyLength(keyValue);
+
+ Bundle extras = new Bundle();
+ extras.putString(ContactKeys.LOOKUP_KEY, Objects.requireNonNull(lookupKey));
+ extras.putString(ContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId));
+ extras.putString(ContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId));
+ extras.putByteArray(ContactKeys.KEY_VALUE, Objects.requireNonNull(keyValue));
+
+ nullSafeCall(mContentResolver,
+ ContactKeys.UPDATE_OR_INSERT_CONTACT_KEY_METHOD, extras);
+ }
+
+ /**
+ * Retrieves a contact key entry given the lookup key, device ID, accountId and inferred
+ * caller package name.
+ *
+ * @param lookupKey the value that references the contact
+ * @param deviceId an app-specified identifier for the device
+ * @param accountId an app-specified identifier for the account
+ *
+ * @return a {@link ContactKey} object containing the contact key information,
+ * or null if no contact key is found.
+ */
+ @RequiresPermission(android.Manifest.permission.READ_CONTACTS)
+ @Nullable
+ public ContactKey getContactKey(
+ @NonNull String lookupKey,
+ @NonNull String deviceId,
+ @NonNull String accountId) {
+ Bundle extras = new Bundle();
+ extras.putString(ContactKeys.LOOKUP_KEY, Objects.requireNonNull(lookupKey));
+ extras.putString(ContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId));
+ extras.putString(ContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId));
+
+ Bundle response = nullSafeCall(mContentResolver,
+ ContactKeys.GET_CONTACT_KEY_METHOD, extras);
+
+ if (response == null) {
+ return null;
+ }
+ return response.getParcelable(ContactKeys.KEY_CONTACT_KEY, ContactKey.class);
+ }
+
+ /**
+ * Retrieves all contact key entries that belong to apps visible to the caller.
+ * The keys will be stripped of deviceId, timeUpdated and keyValue data.
+ *
+ * @param lookupKey the value that references the contact
+ *
+ * @return a list of {@link ContactKey} objects containing the contact key
+ * information, or an empty list if no keys are found.
+ */
+ @RequiresPermission(android.Manifest.permission.READ_CONTACTS)
+ @NonNull
+ public List<ContactKey> getAllContactKeys(@NonNull String lookupKey) {
+ Bundle extras = new Bundle();
+ extras.putString(ContactKeys.LOOKUP_KEY, Objects.requireNonNull(lookupKey));
+
+ Bundle response = nullSafeCall(mContentResolver,
+ ContactKeys.GET_ALL_CONTACT_KEYS_METHOD, extras);
+
+ if (response == null) {
+ return new ArrayList<>();
+ }
+ List<ContactKey> value = response.getParcelableArrayList(ContactKeys.KEY_CONTACT_KEYS,
+ ContactKey.class);
+ if (value == null) {
+ return new ArrayList<>();
+ }
+ return value;
+ }
+
+ /**
+ * Retrieves all contact key entries for a given lookupKey that belong to the caller app.
+ *
+ * @param lookupKey the value that references the contact
+ *
+ * @return a list of {@link ContactKey} objects containing the contact key
+ * information, or an empty list if no keys are found.
+ */
+ @RequiresPermission(android.Manifest.permission.READ_CONTACTS)
+ @NonNull
+ public List<ContactKey> getOwnerContactKeys(@NonNull String lookupKey) {
+ Bundle extras = new Bundle();
+ extras.putString(ContactKeys.LOOKUP_KEY, Objects.requireNonNull(lookupKey));
+
+ Bundle response = nullSafeCall(mContentResolver,
+ ContactKeys.GET_OWNER_CONTACT_KEYS_METHOD, extras);
+
+ if (response == null) {
+ return new ArrayList<>();
+ }
+ List<ContactKey> value = response.getParcelableArrayList(ContactKeys.KEY_CONTACT_KEYS,
+ ContactKey.class);
+ if (value == null) {
+ return new ArrayList<>();
+ }
+ return value;
+ }
+
+ /**
+ * Updates a contact key entry's local verification state that belongs to the caller app.
+ *
+ * @param lookupKey the value that references the contact
+ * @param deviceId an app-specified identifier for the device
+ * @param accountId an app-specified identifier for the account
+ * @param localVerificationState the new local verification state
+ *
+ * @return true if the entry was updated, false otherwise.
+ */
+ @RequiresPermission(android.Manifest.permission.WRITE_CONTACTS)
+ public boolean updateContactKeyLocalVerificationState(@NonNull String lookupKey,
+ @NonNull String deviceId,
+ @NonNull String accountId,
+ @VerificationState int localVerificationState) {
+ validateVerificationState(localVerificationState);
+
+ Bundle extras = new Bundle();
+ extras.putString(ContactKeys.LOOKUP_KEY, Objects.requireNonNull(lookupKey));
+ extras.putString(ContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId));
+ extras.putString(ContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId));
+ extras.putInt(ContactKeys.LOCAL_VERIFICATION_STATE, localVerificationState);
+
+ Bundle response = nullSafeCall(mContentResolver,
+ ContactKeys.UPDATE_CONTACT_KEY_LOCAL_VERIFICATION_STATE_METHOD, extras);
+
+ return response != null && response.getBoolean(ContactKeys.KEY_UPDATED_ROWS);
+ }
+
+ /**
+ * Updates a contact key entry's remote verification state that belongs to the caller app.
+ *
+ * @param lookupKey the value that references the contact
+ * @param deviceId an app-specified identifier for the device
+ * @param accountId an app-specified identifier for the account
+ * @param remoteVerificationState the new remote verification state
+ *
+ * @return true if the entry was updated, false otherwise.
+ */
+ @RequiresPermission(android.Manifest.permission.WRITE_CONTACTS)
+ public boolean updateContactKeyRemoteVerificationState(@NonNull String lookupKey,
+ @NonNull String deviceId,
+ @NonNull String accountId,
+ @VerificationState int remoteVerificationState) {
+ validateVerificationState(remoteVerificationState);
+
+ Bundle extras = new Bundle();
+ extras.putString(ContactKeys.LOOKUP_KEY, Objects.requireNonNull(lookupKey));
+ extras.putString(ContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId));
+ extras.putString(ContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId));
+ extras.putInt(ContactKeys.REMOTE_VERIFICATION_STATE, remoteVerificationState);
+
+ Bundle response = nullSafeCall(mContentResolver,
+ ContactKeys.UPDATE_CONTACT_KEY_REMOTE_VERIFICATION_STATE_METHOD, extras);
+
+ return response != null && response.getBoolean(ContactKeys.KEY_UPDATED_ROWS);
+ }
+
+ private static void validateVerificationState(int verificationState) {
+ if (verificationState != UNVERIFIED
+ && verificationState != VERIFICATION_FAILED
+ && verificationState != VERIFIED) {
+ throw new IllegalArgumentException("Verification state value "
+ + verificationState + " is not supported");
+ }
+ }
+
+ /**
+ * Removes a contact key entry that belongs to the caller app.
+ *
+ * @param lookupKey the value that references the contact
+ * @param deviceId an app-specified identifier for the device
+ * @param accountId an app-specified identifier for the account
+ *
+ * @return true if the entry was removed, false otherwise.
+ */
+ @RequiresPermission(android.Manifest.permission.WRITE_CONTACTS)
+ public boolean removeContactKey(@NonNull String lookupKey,
+ @NonNull String deviceId,
+ @NonNull String accountId) {
+ Bundle extras = new Bundle();
+ extras.putString(ContactKeys.LOOKUP_KEY, Objects.requireNonNull(lookupKey));
+ extras.putString(ContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId));
+ extras.putString(ContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId));
+
+ Bundle response = nullSafeCall(mContentResolver,
+ ContactKeys.REMOVE_CONTACT_KEY_METHOD, extras);
+
+ return response != null && response.getBoolean(ContactKeys.KEY_UPDATED_ROWS);
+ }
+
+ /**
+ * Inserts a new entry into the self keys table or updates one if it already exists.
+
+ * @param deviceId an app-specified identifier for the device
+ * @param accountId an app-specified identifier for the account
+ * @param keyValue the raw bytes for the key (max size is {@link #getMaxKeySizeBytes} bytes)
+ *
+ * @return true if the entry was added or updated, false otherwise.
+ */
+ @RequiresPermission(android.Manifest.permission.WRITE_CONTACTS)
+ public boolean updateOrInsertSelfKey(@NonNull String deviceId,
+ @NonNull String accountId,
+ @NonNull byte[] keyValue) {
+ validateKeyLength(keyValue);
+
+ Bundle extras = new Bundle();
+ extras.putString(ContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId));
+ extras.putString(ContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId));
+ extras.putByteArray(ContactKeys.KEY_VALUE, Objects.requireNonNull(keyValue));
+
+ Bundle response = nullSafeCall(mContentResolver,
+ ContactKeys.UPDATE_OR_INSERT_SELF_KEY_METHOD, extras);
+
+ return response != null && response.getBoolean(ContactKeys.KEY_UPDATED_ROWS);
+ }
+
+ private static void validateKeyLength(byte[] keyValue) {
+ Objects.requireNonNull(keyValue);
+ if (keyValue.length == 0 || keyValue.length > getMaxKeySizeBytes()) {
+ throw new IllegalArgumentException("Key value length is " + keyValue.length + "."
+ + " Should be more than 0 and less than " + getMaxKeySizeBytes());
+ }
+ }
+
+ /**
+ * Updates a self key entry's remote verification state.
+ *
+ * @param deviceId an app-specified identifier for the device
+ * @param accountId an app-specified identifier for the account
+ * @param remoteVerificationState the new remote verification state
+ *
+ * @return true if the entry was updated, false otherwise.
+ */
+ @RequiresPermission(android.Manifest.permission.WRITE_CONTACTS)
+ public boolean updateSelfKeyRemoteVerificationState(@NonNull String deviceId,
+ @NonNull String accountId,
+ @VerificationState int remoteVerificationState) {
+ validateVerificationState(remoteVerificationState);
+
+ Bundle extras = new Bundle();
+ extras.putString(ContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId));
+ extras.putString(ContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId));
+ extras.putInt(ContactKeys.REMOTE_VERIFICATION_STATE, remoteVerificationState);
+
+ Bundle response = nullSafeCall(mContentResolver,
+ ContactKeys.UPDATE_SELF_KEY_REMOTE_VERIFICATION_STATE_METHOD, extras);
+
+ return response != null && response.getBoolean(ContactKeys.KEY_UPDATED_ROWS);
+ }
+
+ /**
+ * Maximum size of a contact key.
+ */
+ public static int getMaxKeySizeBytes() {
+ return MAX_KEY_SIZE_BYTES;
+ }
+
+ /**
+ * Returns a self key entry given the deviceId and the inferred package name of the caller.
+ *
+ * @param deviceId an app-specified identifier for the device
+ * @param accountId an app-specified identifier for the account
+ *
+ * @return a {@link SelfKey} object containing the self key information, or null if no self key
+ * is found.
+ */
+ @RequiresPermission(android.Manifest.permission.READ_CONTACTS)
+ @Nullable
+ public SelfKey getSelfKey(@NonNull String deviceId,
+ @NonNull String accountId) {
+ Bundle extras = new Bundle();
+ extras.putString(ContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId));
+ extras.putString(ContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId));
+
+ Bundle response = nullSafeCall(mContentResolver,
+ ContactKeys.GET_SELF_KEY_METHOD, extras);
+
+ if (response == null) {
+ return null;
+ }
+ return response.getParcelable(ContactKeys.KEY_CONTACT_KEY, SelfKey.class);
+ }
+
+ /**
+ * Returns all self key entries that belong to apps visible to the caller.
+ * The keys will be stripped of deviceId, timeUpdated and keyValue data.
+ *
+ * @return a list of {@link SelfKey} objects containing the self key information, or
+ * an empty list if no keys are found.
+ */
+ @RequiresPermission(android.Manifest.permission.READ_CONTACTS)
+ @NonNull
+ public List<SelfKey> getAllSelfKeys() {
+ Bundle extras = new Bundle();
+
+ Bundle response = nullSafeCall(mContentResolver, ContactKeys.GET_ALL_SELF_KEYS_METHOD,
+ extras);
+
+ if (response == null) {
+ return new ArrayList<>();
+ }
+ List<SelfKey> value = response.getParcelableArrayList(ContactKeys.KEY_CONTACT_KEYS,
+ SelfKey.class);
+ if (value == null) {
+ return new ArrayList<>();
+ }
+ return value;
+ }
+
+ /**
+ * Returns all self key entries that are owned by the caller app.
+ *
+ * @return a list of {@link SelfKey} objects containing the self key information, or
+ * an empty list if no keys are found.
+ */
+ @RequiresPermission(android.Manifest.permission.READ_CONTACTS)
+ @NonNull
+ public List<SelfKey> getOwnerSelfKeys() {
+ Bundle extras = new Bundle();
+
+ Bundle response = nullSafeCall(mContentResolver, ContactKeys.GET_OWNER_SELF_KEYS_METHOD,
+ extras);
+
+ if (response == null) {
+ return new ArrayList<>();
+ }
+ List<SelfKey> value = response.getParcelableArrayList(ContactKeys.KEY_CONTACT_KEYS,
+ SelfKey.class);
+ if (value == null) {
+ return new ArrayList<>();
+ }
+ return value;
+ }
+
+ /**
+ * Removes a self key entry given the deviceId and the inferred package name of the caller.
+
+ * @param deviceId an app-specified identifier for the device
+ * @param accountId an app-specified identifier for the account
+ *
+ * @return true if the entry was removed, false otherwise.
+ */
+ @RequiresPermission(android.Manifest.permission.WRITE_CONTACTS)
+ public boolean removeSelfKey(@NonNull String deviceId,
+ @NonNull String accountId) {
+ Bundle extras = new Bundle();
+ extras.putString(ContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId));
+ extras.putString(ContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId));
+
+ Bundle response = nullSafeCall(mContentResolver,
+ ContactKeys.REMOVE_SELF_KEY_METHOD, extras);
+
+ return response != null && response.getBoolean(ContactKeys.KEY_UPDATED_ROWS);
+ }
+
+ private Bundle nullSafeCall(@NonNull ContentResolver resolver, @NonNull String method,
+ @Nullable Bundle extras) {
+ try (ContentProviderClient client = resolver.acquireContentProviderClient(AUTHORITY_URI)) {
+ return client.call(method, null, extras);
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ }
+
+ /**
+ * Possible values of verification state.
+ * @hide
+ */
+ @IntDef(prefix = {"VERIFICATION_STATE_"}, value = {
+ UNVERIFIED,
+ VERIFICATION_FAILED,
+ VERIFIED
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface VerificationState {}
+
+ /**
+ * Unverified state of a contact E2EE key.
+ */
+ public static final int UNVERIFIED = 0;
+ /**
+ * Failed verification state of a contact E2EE key.
+ */
+ public static final int VERIFICATION_FAILED = 1;
+ /**
+ * Verified state of a contact E2EE key.
+ */
+ public static final int VERIFIED = 2;
+
+ /** @hide */
+ public static final class ContactKeys {
+
+ private ContactKeys() {}
+
+ /**
+ * <p>
+ * An opaque value that contains hints on how to find the contact if
+ * its row id changed as a result of a sync or aggregation.
+ * </p>
+ */
+ public static final String LOOKUP_KEY = "lookup";
+
+ /**
+ * <p>
+ * An app-specified identifier for the device for which the contact key can be used.
+ * </p>
+ */
+ public static final String DEVICE_ID = "device_id";
+
+ /**
+ * <p>
+ * An app-specified identifier for the account for which the contact key can be used.
+ * Usually a phone number.
+ * </p>
+ */
+ public static final String ACCOUNT_ID = "account_id";
+
+ /**
+ * <p>
+ * The display name for the contact.
+ * </p>
+ */
+ public static final String DISPLAY_NAME = "display_name";
+
+ /**
+ * <p>
+ * The phone number as the user entered it.
+ * </p>
+ */
+ public static final String PHONE_NUMBER = "number";
+
+ /**
+ * <p>
+ * The email address.
+ * </p>
+ */
+ public static final String EMAIL_ADDRESS = "address";
+
+ /**
+ * <p>
+ * Timestamp at which the key was updated.
+ * </p>
+ */
+ public static final String TIME_UPDATED = "time_updated";
+
+ /**
+ * <p>
+ * The raw bytes for the key.
+ * </p>
+ */
+ public static final String KEY_VALUE = "key_value";
+
+ /**
+ * <p>
+ * The package name of the package that created the key.
+ * </p>
+ */
+ public static final String OWNER_PACKAGE_NAME = "owner_package_name";
+
+ /**
+ * <p>
+ * Describes the local verification state for the key, for instance QR-code based
+ * verification.
+ * </p>
+ */
+ public static final String LOCAL_VERIFICATION_STATE = "local_verification_state";
+
+ /**
+ * <p>
+ * Describes the remote verification state for the key, for instance through a key
+ * transparency server.
+ * </p>
+ */
+ public static final String REMOTE_VERIFICATION_STATE = "remote_verification_state";
+
+ /**
+ * The method to invoke in order to add a new key for a contact.
+ */
+ public static final String UPDATE_OR_INSERT_CONTACT_KEY_METHOD = "updateOrInsertContactKey";
+
+ /**
+ * The method to invoke in order to retrieve key for a single contact.
+ */
+ public static final String GET_CONTACT_KEY_METHOD = "getContactKey";
+
+ /**
+ * The method to invoke in order to retrieve all contact keys.
+ */
+ public static final String GET_ALL_CONTACT_KEYS_METHOD = "getAllContactKeys";
+
+ /**
+ * The method to invoke in order to retrieve contact keys that belong to the caller.
+ */
+ public static final String GET_OWNER_CONTACT_KEYS_METHOD = "getOwnerContactKeys";
+
+ /**
+ * The method to invoke in order to update a contact key local verification state.
+ */
+ public static final String UPDATE_CONTACT_KEY_LOCAL_VERIFICATION_STATE_METHOD =
+ "updateContactKeyLocalVerificationState";
+
+ /**
+ * The method to invoke in order to update a contact key remote verification state.
+ */
+ public static final String UPDATE_CONTACT_KEY_REMOTE_VERIFICATION_STATE_METHOD =
+ "updateContactKeyRemoteVerificationState";
+
+ /**
+ * The method to invoke in order to remove a contact key.
+ */
+ public static final String REMOVE_CONTACT_KEY_METHOD = "removeContactKey";
+
+ /**
+ * The method to invoke in order to add a new self key.
+ */
+ public static final String UPDATE_OR_INSERT_SELF_KEY_METHOD = "updateOrInsertSelfKey";
+
+ /**
+ * The method to invoke in order to update a self key remote verification state.
+ */
+ public static final String UPDATE_SELF_KEY_REMOTE_VERIFICATION_STATE_METHOD =
+ "updateSelfKeyRemoteVerificationState";
+
+ /**
+ * The method to invoke in order to retrieve a self key.
+ */
+ public static final String GET_SELF_KEY_METHOD = "getSelfKey";
+
+ /**
+ * The method to invoke in order to retrieve all self keys.
+ */
+ public static final String GET_ALL_SELF_KEYS_METHOD = "getAllSelfKeys";
+
+ /**
+ * The method to invoke in order to retrieve self keys that belong to the caller.
+ */
+ public static final String GET_OWNER_SELF_KEYS_METHOD = "getOwnerSelfKeys";
+
+ /**
+ * The method to invoke in order to remove a new self key.
+ */
+ public static final String REMOVE_SELF_KEY_METHOD = "removeSelfKey";
+
+ /**
+ * Key in the incoming Bundle for all the contact keys.
+ */
+ public static final String KEY_CONTACT_KEYS = "key_contact_keys";
+
+ /**
+ * Key in the incoming Bundle for a single contact key.
+ */
+ public static final String KEY_CONTACT_KEY = "key_contact_key";
+
+ /**
+ * Key in the incoming Bundle for a number of modified rows.
+ */
+ public static final String KEY_UPDATED_ROWS = "key_updated_rows";
+ }
+
+ /**
+ * A parcelable class encapsulating other users' E2EE contact key.
+ */
+ public static final class ContactKey implements Parcelable {
+ /**
+ * An app-specified identifier for the device for which the contact key can be used.
+ */
+ private final String mDeviceId;
+
+ /**
+ * An app-specified identifier for the account for which the contact key can be used.
+ * Usually a phone number.
+ */
+ private final String mAccountId;
+
+ /**
+ * Owner application package name.
+ */
+ private final String mOwnerPackageName;
+
+ /**
+ * Timestamp at which the key was updated.
+ */
+ private final long mTimeUpdated;
+
+ /**
+ * The raw bytes for the key.
+ */
+ private final byte[] mKeyValue;
+
+ /**
+ * Describes the local verification state for the key, for instance QR-code based
+ * verification.
+ */
+ private final int mLocalVerificationState;
+
+ /**
+ * Describes the remote verification state for the key, for instance through a key
+ * transparency server.
+ */
+ private final int mRemoteVerificationState;
+
+ /**
+ * The display name for the contact.
+ */
+ private final String mDisplayName;
+
+ /**
+ * The phone number as the user entered it.
+ */
+ private final String mPhoneNumber;
+
+ /**
+ * The email address.
+ */
+ private final String mEmailAddress;
+
+ /**
+ * @hide
+ */
+ public ContactKey(@Nullable String deviceId, @NonNull String accountId,
+ @NonNull String ownerPackageName, long timeUpdated, @Nullable byte[] keyValue,
+ @VerificationState int localVerificationState,
+ @VerificationState int remoteVerificationState,
+ @Nullable String displayName,
+ @Nullable String phoneNumber, @Nullable String emailAddress) {
+ this.mDeviceId = deviceId;
+ this.mAccountId = accountId;
+ this.mOwnerPackageName = ownerPackageName;
+ this.mTimeUpdated = timeUpdated;
+ this.mKeyValue = keyValue == null ? null : Arrays.copyOf(keyValue, keyValue.length);
+ this.mLocalVerificationState = localVerificationState;
+ this.mRemoteVerificationState = remoteVerificationState;
+ this.mDisplayName = displayName;
+ this.mPhoneNumber = phoneNumber;
+ this.mEmailAddress = emailAddress;
+ }
+
+ /**
+ * Gets the app-specified identifier for the device for which the contact key can be used.
+ * Returns null if the app doesn't have the required visibility into the contact key.
+ *
+ * @return An app-specified identifier for the device.
+ */
+ @Nullable
+ public String getDeviceId() {
+ return mDeviceId;
+ }
+
+ /**
+ * Gets the app-specified identifier for the account for which the contact key can be used.
+ * Usually a phone number.
+ *
+ * @return An app-specified identifier for the account.
+ */
+ @NonNull
+ public String getAccountId() {
+ return mAccountId;
+ }
+
+ /**
+ * Gets the owner application package name.
+ *
+ * @return The owner application package name.
+ */
+ @NonNull
+ public String getOwnerPackageName() {
+ return mOwnerPackageName;
+ }
+
+ /**
+ * Gets the timestamp at which the key was updated. Returns -1 if the app doesn't have the
+ * required visibility into the contact key.
+ *
+ * @return The timestamp at which the key was updated in the System.currentTimeMillis()
+ * base.
+ */
+ public long getTimeUpdated() {
+ return mTimeUpdated;
+ }
+
+ /**
+ * Gets the raw bytes for the key.
+ * Returns null if the app doesn't have the required visibility into the contact key.
+ *
+ * @return A copy of the raw bytes for the key.
+ */
+ @Nullable
+ public byte[] getKeyValue() {
+ return mKeyValue == null ? null : Arrays.copyOf(mKeyValue, mKeyValue.length);
+ }
+
+ /**
+ * Gets the local verification state for the key, for instance QR-code based verification.
+ *
+ * @return The local verification state for the key.
+ */
+ public @VerificationState int getLocalVerificationState() {
+ return mLocalVerificationState;
+ }
+
+ /**
+ * Gets the remote verification state for the key, for instance through a key transparency
+ * server.
+ *
+ * @return The remote verification state for the key.
+ */
+ public @VerificationState int getRemoteVerificationState() {
+ return mRemoteVerificationState;
+ }
+
+ /**
+ * Gets the display name for the contact.
+ *
+ * @return The display name for the contact.
+ */
+ @Nullable
+ public String getDisplayName() {
+ return mDisplayName;
+ }
+
+ /**
+ * Gets the phone number as the user entered it.
+ *
+ * @return The phone number as the user entered it.
+ */
+ @Nullable
+ public String getPhoneNumber() {
+ return mPhoneNumber;
+ }
+
+ /**
+ * Gets the email address.
+ *
+ * @return The email address.
+ */
+ @Nullable
+ public String getEmailAddress() {
+ return mEmailAddress;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mDeviceId, mAccountId, mOwnerPackageName, mTimeUpdated,
+ Arrays.hashCode(mKeyValue), mLocalVerificationState, mRemoteVerificationState,
+ mDisplayName, mPhoneNumber, mEmailAddress);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null) return false;
+ if (obj == this) return true;
+
+ if (!(obj instanceof ContactKey toCompare)) {
+ return false;
+ }
+
+ return Objects.equals(mDeviceId, toCompare.mDeviceId)
+ && Objects.equals(mAccountId, toCompare.mAccountId)
+ && Objects.equals(mOwnerPackageName, toCompare.mOwnerPackageName)
+ && mTimeUpdated == toCompare.mTimeUpdated
+ && Arrays.equals(mKeyValue, toCompare.mKeyValue)
+ && mLocalVerificationState == toCompare.mLocalVerificationState
+ && mRemoteVerificationState == toCompare.mRemoteVerificationState
+ && Objects.equals(mDisplayName, toCompare.mDisplayName)
+ && Objects.equals(mPhoneNumber, toCompare.mPhoneNumber)
+ && Objects.equals(mEmailAddress, toCompare.mEmailAddress);
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeString8(mDeviceId);
+ dest.writeString8(mAccountId);
+ dest.writeString8(mOwnerPackageName);
+ dest.writeLong(mTimeUpdated);
+ dest.writeInt(mKeyValue != null ? mKeyValue.length : ARRAY_IS_NULL);
+ if (mKeyValue != null) {
+ dest.writeByteArray(mKeyValue);
+ }
+ dest.writeInt(mLocalVerificationState);
+ dest.writeInt(mRemoteVerificationState);
+ dest.writeString8(mDisplayName);
+ dest.writeString8(mPhoneNumber);
+ dest.writeString8(mEmailAddress);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @NonNull
+ public static final Creator<ContactKey> CREATOR =
+ new Creator<>() {
+ @Override
+ public ContactKey createFromParcel(Parcel source) {
+ String deviceId = source.readString8();
+ String accountId = source.readString8();
+ String ownerPackageName = source.readString8();
+ long timeUpdated = source.readLong();
+ int keyValueLength = source.readInt();
+ byte[] keyValue;
+ if (keyValueLength > 0) {
+ keyValue = new byte[keyValueLength];
+ source.readByteArray(keyValue);
+ } else {
+ keyValue = null;
+ }
+ int localVerificationState = source.readInt();
+ int remoteVerificationState = source.readInt();
+ String displayName = source.readString8();
+ String number = source.readString8();
+ String address = source.readString8();
+ return new ContactKey(deviceId, accountId, ownerPackageName,
+ timeUpdated, keyValue, localVerificationState,
+ remoteVerificationState, displayName, number, address);
+ }
+
+ @Override
+ public ContactKey[] newArray(int size) {
+ return new ContactKey[size];
+ }
+ };
+ }
+
+ /**
+ * A parcelable class encapsulating self E2EE contact key.
+ */
+ public static final class SelfKey implements Parcelable {
+ /**
+ * An app-specified identifier for the device for which the contact key can be used.
+ */
+ private final String mDeviceId;
+
+ /**
+ * An app-specified identifier for the account for which the contact key can be used.
+ * Usually a phone number.
+ */
+ private final String mAccountId;
+
+ /**
+ * Owner application package name.
+ */
+ private final String mOwnerPackageName;
+
+ /**
+ * Timestamp at which the key was updated.
+ */
+ private final long mTimeUpdated;
+
+ /**
+ * The raw bytes for the key.
+ */
+ private final byte[] mKeyValue;
+
+
+ /**
+ * Describes the remote verification state for the key, for instance through a key
+ * transparency server.
+ */
+ private final int mRemoteVerificationState;
+
+ /**
+ * @hide
+ */
+ public SelfKey(@Nullable String deviceId, @NonNull String accountId,
+ @NonNull String ownerPackageName, long timeUpdated, @Nullable byte[] keyValue,
+ @VerificationState int remoteVerificationState) {
+ this.mDeviceId = deviceId;
+ this.mAccountId = accountId;
+ this.mOwnerPackageName = ownerPackageName;
+ this.mTimeUpdated = timeUpdated;
+ this.mKeyValue = keyValue == null ? null : Arrays.copyOf(keyValue, keyValue.length);
+ this.mRemoteVerificationState = remoteVerificationState;
+ }
+
+ /**
+ * Gets the app-specified identifier for the device for which the contact key can be used.
+ * Returns null if the app doesn't have the required visibility into the contact key.
+ *
+ * @return An app-specified identifier for the device.
+ */
+ @Nullable
+ public String getDeviceId() {
+ return mDeviceId;
+ }
+
+ /**
+ * Gets the app-specified identifier for the account for which the contact key can be used.
+ * Usually a phone number.
+ *
+ * @return An app-specified identifier for the device.
+ */
+ @NonNull
+ public String getAccountId() {
+ return mAccountId;
+ }
+
+ /**
+ * Gets the owner application package name.
+ *
+ * @return The owner application package name.
+ */
+ @NonNull
+ public String getOwnerPackageName() {
+ return mOwnerPackageName;
+ }
+
+ /**
+ * Gets the timestamp at which the key was updated. Returns -1 if the app doesn't have the
+ * required visibility into the contact key.
+ *
+ * @return The timestamp at which the key was updated in the System.currentTimeMillis()
+ * base.
+ */
+ public long getTimeUpdated() {
+ return mTimeUpdated;
+ }
+
+ /**
+ * Gets the raw bytes for the key.
+ * Returns null if the app doesn't have the required visibility into the contact key.
+ *
+ * @return A copy of the raw bytes for the key.
+ */
+ @Nullable
+ public byte[] getKeyValue() {
+ return mKeyValue == null ? null : Arrays.copyOf(mKeyValue, mKeyValue.length);
+ }
+
+ /**
+ * Gets the remote verification state for the key, for instance through a key transparency
+ * server.
+ *
+ * @return The remote verification state for the key.
+ */
+ public @VerificationState int getRemoteVerificationState() {
+ return mRemoteVerificationState;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mDeviceId, mAccountId, mOwnerPackageName, mTimeUpdated,
+ Arrays.hashCode(mKeyValue), mRemoteVerificationState);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null) return false;
+ if (obj == this) return true;
+
+ if (!(obj instanceof SelfKey toCompare)) {
+ return false;
+ }
+
+ return Objects.equals(mDeviceId, toCompare.mDeviceId)
+ && Objects.equals(mAccountId, toCompare.mAccountId)
+ && Objects.equals(mOwnerPackageName, toCompare.mOwnerPackageName)
+ && mTimeUpdated == toCompare.mTimeUpdated
+ && Arrays.equals(mKeyValue, toCompare.mKeyValue)
+ && mRemoteVerificationState == toCompare.mRemoteVerificationState;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeString8(mDeviceId);
+ dest.writeString8(mAccountId);
+ dest.writeString8(mOwnerPackageName);
+ dest.writeLong(mTimeUpdated);
+ dest.writeInt(mKeyValue != null ? mKeyValue.length : ARRAY_IS_NULL);
+ if (mKeyValue != null) {
+ dest.writeByteArray(mKeyValue);
+ }
+ dest.writeInt(mRemoteVerificationState);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @NonNull
+ public static final Creator<SelfKey> CREATOR =
+ new Creator<>() {
+ @Override
+ public SelfKey createFromParcel(Parcel source) {
+ String deviceId = source.readString8();
+ String accountId = source.readString8();
+ String ownerPackageName = source.readString8();
+ long timeUpdated = source.readLong();
+ int keyValueLength = source.readInt();
+ byte[] keyValue;
+ if (keyValueLength > 0) {
+ keyValue = new byte[keyValueLength];
+ source.readByteArray(keyValue);
+ } else {
+ keyValue = null;
+ }
+ int remoteVerificationState = source.readInt();
+ return new SelfKey(deviceId, accountId, ownerPackageName,
+ timeUpdated, keyValue, remoteVerificationState);
+ }
+
+ @Override
+ public SelfKey[] newArray(int size) {
+ return new SelfKey[size];
+ }
+ };
+ }
+}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 11edcaf..e238080 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -4932,6 +4932,7 @@
*
* @hide
*/
+ @Readable
public static final String DEFAULT_DEVICE_FONT_SCALE = "device_font_scale";
/**
diff --git a/core/java/android/provider/flags.aconfig b/core/java/android/provider/flags.aconfig
index 3dd7692..0f12b13 100644
--- a/core/java/android/provider/flags.aconfig
+++ b/core/java/android/provider/flags.aconfig
@@ -6,3 +6,10 @@
description: "Enable Settings.System.resetToDefault APIs."
bug: "279083734"
}
+
+flag {
+ name: "user_keys"
+ namespace: "privacy_infra_policy"
+ description: "This flag controls new E2EE contact keys API"
+ bug: "290696572"
+}
diff --git a/core/java/android/security/responsible_apis_flags.aconfig b/core/java/android/security/responsible_apis_flags.aconfig
index fe6c4a4..0bae459 100644
--- a/core/java/android/security/responsible_apis_flags.aconfig
+++ b/core/java/android/security/responsible_apis_flags.aconfig
@@ -27,3 +27,17 @@
description: "Enables the content URI permission APIs"
bug: "293467489"
}
+
+flag {
+ name: "enforce_intent_filter_match"
+ namespace: "responsible_apis"
+ description: "Make delivered intents match components' intent filters"
+ bug: "293560872"
+}
+
+flag {
+ name: "block_null_action_intents"
+ namespace: "responsible_apis"
+ description: "Do not allow intents without an action to match any intent filters"
+ bug: "293560872"
+}
diff --git a/core/java/android/service/autofill/AutofillService.java b/core/java/android/service/autofill/AutofillService.java
index 5ad2502..298bdb8 100644
--- a/core/java/android/service/autofill/AutofillService.java
+++ b/core/java/android/service/autofill/AutofillService.java
@@ -622,6 +622,15 @@
new FillCallback(callback, request.getId())));
}
+ @Override
+ public void onConvertCredentialRequest(
+ @NonNull ConvertCredentialRequest convertCredentialRequest,
+ @NonNull IConvertCredentialCallback convertCredentialCallback) {
+ mHandler.sendMessage(obtainMessage(
+ AutofillService::onConvertCredentialRequest,
+ AutofillService.this, convertCredentialRequest,
+ new ConvertCredentialCallback(convertCredentialCallback)));
+ }
@Override
public void onFillCredentialRequest(FillRequest request, IFillCallback callback,
@@ -707,7 +716,19 @@
*/
public void onFillCredentialRequest(@NonNull FillRequest request,
@NonNull CancellationSignal cancellationSignal, @NonNull FillCallback callback,
- IAutoFillManagerClient autofillClientCallback) {}
+ @NonNull IAutoFillManagerClient autofillClientCallback) {}
+
+ /**
+ * Called by the Android system to convert a credential manager response to a dataset
+ *
+ * @param convertCredentialRequest the request that has the original credential manager response
+ * @param convertCredentialCallback callback used to notify the result of the request.
+ *
+ * @hide
+ */
+ public void onConvertCredentialRequest(
+ @NonNull ConvertCredentialRequest convertCredentialRequest,
+ @NonNull ConvertCredentialCallback convertCredentialCallback){}
/**
* Called when the user requests the service to save the contents of a screen.
diff --git a/core/java/android/service/autofill/ConvertCredentialCallback.java b/core/java/android/service/autofill/ConvertCredentialCallback.java
new file mode 100644
index 0000000..a39f011
--- /dev/null
+++ b/core/java/android/service/autofill/ConvertCredentialCallback.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.autofill;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.RemoteException;
+
+/**
+ * <p><code>ConvertCredentialCallback</code> handles convertCredentialResponse from Autofill
+ * Service.
+ *
+ * @hide
+ */
+public final class ConvertCredentialCallback {
+
+ private static final String TAG = "ConvertCredentialCallback";
+
+ private final IConvertCredentialCallback mCallback;
+
+ /** @hide */
+ public ConvertCredentialCallback(IConvertCredentialCallback callback) {
+ mCallback = callback;
+ }
+
+ /**
+ * Notifies the Android System that a convertCredentialRequest was fulfilled by the service.
+ *
+ * @param convertCredentialResponse the result
+ */
+ public void onSuccess(@NonNull ConvertCredentialResponse convertCredentialResponse) {
+ try {
+ mCallback.onSuccess(convertCredentialResponse);
+ } catch (RemoteException e) {
+ e.rethrowAsRuntimeException();
+ }
+ }
+
+ /**
+ * Notifies the Android System that a convert credential request has failed
+ *
+ * @param message the error message
+ */
+ public void onFailure(@Nullable CharSequence message) {
+ try {
+ mCallback.onFailure(message);
+ } catch (RemoteException e) {
+ e.rethrowAsRuntimeException();
+ }
+ }
+}
diff --git a/core/java/android/credentials/ui/UiResult.java b/core/java/android/service/autofill/ConvertCredentialRequest.aidl
similarity index 68%
copy from core/java/android/credentials/ui/UiResult.java
copy to core/java/android/service/autofill/ConvertCredentialRequest.aidl
index 692584d..79681e2 100644
--- a/core/java/android/credentials/ui/UiResult.java
+++ b/core/java/android/service/autofill/ConvertCredentialRequest.aidl
@@ -1,11 +1,11 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
+/**
+ * Copyright (c) 2024, The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -14,11 +14,6 @@
* limitations under the License.
*/
-package android.credentials.ui;
+package android.service.autofill;
-/**
- * Base class for different types of ui results.
- *
- * @hide
- */
-public interface UiResult {}
+parcelable ConvertCredentialRequest;
\ No newline at end of file
diff --git a/core/java/android/service/autofill/ConvertCredentialRequest.java b/core/java/android/service/autofill/ConvertCredentialRequest.java
new file mode 100644
index 0000000..d2d7556
--- /dev/null
+++ b/core/java/android/service/autofill/ConvertCredentialRequest.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.autofill;
+
+import android.annotation.NonNull;
+import android.credentials.GetCredentialResponse;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.util.DataClass;
+
+
+/**
+ * This class represents a request to an autofill service to convert the credential manager response
+ * to a dataset.
+ *
+ * @hide
+ */
+@DataClass(
+ genToString = true,
+ genHiddenConstructor = true,
+ genHiddenConstDefs = true)
+public final class ConvertCredentialRequest implements Parcelable {
+ private final @NonNull GetCredentialResponse mGetCredentialResponse;
+ private final @NonNull Bundle mClientState;
+
+
+
+ // Code below generated by codegen v1.0.23.
+ //
+ // DO NOT MODIFY!
+ // CHECKSTYLE:OFF Generated code
+ //
+ // To regenerate run:
+ // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/service/autofill/ConvertCredentialRequest.java
+ //
+ // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+ // Settings > Editor > Code Style > Formatter Control
+ //@formatter:off
+
+
+ /**
+ * Creates a new ConvertCredentialRequest.
+ *
+ * @hide
+ */
+ @DataClass.Generated.Member
+ public ConvertCredentialRequest(
+ @NonNull GetCredentialResponse getCredentialResponse,
+ @NonNull Bundle clientState) {
+ this.mGetCredentialResponse = getCredentialResponse;
+ com.android.internal.util.AnnotationValidations.validate(
+ NonNull.class, null, mGetCredentialResponse);
+ this.mClientState = clientState;
+ com.android.internal.util.AnnotationValidations.validate(
+ NonNull.class, null, mClientState);
+
+ // onConstructed(); // You can define this method to get a callback
+ }
+
+ @DataClass.Generated.Member
+ public @NonNull GetCredentialResponse getGetCredentialResponse() {
+ return mGetCredentialResponse;
+ }
+
+ @DataClass.Generated.Member
+ public @NonNull Bundle getClientState() {
+ return mClientState;
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public String toString() {
+ // You can override field toString logic by defining methods like:
+ // String fieldNameToString() { ... }
+
+ return "ConvertCredentialRequest { " +
+ "getCredentialResponse = " + mGetCredentialResponse + ", " +
+ "clientState = " + mClientState +
+ " }";
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ // You can override field parcelling by defining methods like:
+ // void parcelFieldName(Parcel dest, int flags) { ... }
+
+ dest.writeTypedObject(mGetCredentialResponse, flags);
+ dest.writeBundle(mClientState);
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public int describeContents() { return 0; }
+
+ /** @hide */
+ @SuppressWarnings({"unchecked", "RedundantCast"})
+ @DataClass.Generated.Member
+ /* package-private */ ConvertCredentialRequest(@NonNull Parcel in) {
+ // You can override field unparcelling by defining methods like:
+ // static FieldType unparcelFieldName(Parcel in) { ... }
+
+ GetCredentialResponse getCredentialResponse = (GetCredentialResponse) in.readTypedObject(GetCredentialResponse.CREATOR);
+ Bundle clientState = in.readBundle();
+
+ this.mGetCredentialResponse = getCredentialResponse;
+ com.android.internal.util.AnnotationValidations.validate(
+ NonNull.class, null, mGetCredentialResponse);
+ this.mClientState = clientState;
+ com.android.internal.util.AnnotationValidations.validate(
+ NonNull.class, null, mClientState);
+
+ // onConstructed(); // You can define this method to get a callback
+ }
+
+ @DataClass.Generated.Member
+ public static final @NonNull Parcelable.Creator<ConvertCredentialRequest> CREATOR
+ = new Parcelable.Creator<ConvertCredentialRequest>() {
+ @Override
+ public ConvertCredentialRequest[] newArray(int size) {
+ return new ConvertCredentialRequest[size];
+ }
+
+ @Override
+ public ConvertCredentialRequest createFromParcel(@NonNull Parcel in) {
+ return new ConvertCredentialRequest(in);
+ }
+ };
+
+ @DataClass.Generated(
+ time = 1706132305002L,
+ codegenVersion = "1.0.23",
+ sourceFile = "frameworks/base/core/java/android/service/autofill/ConvertCredentialRequest.java",
+ inputSignatures = "private final @android.annotation.NonNull android.credentials.GetCredentialResponse mGetCredentialResponse\nprivate final @android.annotation.NonNull android.os.Bundle mClientState\nclass ConvertCredentialRequest extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genHiddenConstructor=true, genHiddenConstDefs=true)")
+ @Deprecated
+ private void __metadata() {}
+
+
+ //@formatter:on
+ // End of generated code
+
+}
diff --git a/core/java/android/credentials/ui/UiResult.java b/core/java/android/service/autofill/ConvertCredentialResponse.aidl
similarity index 68%
copy from core/java/android/credentials/ui/UiResult.java
copy to core/java/android/service/autofill/ConvertCredentialResponse.aidl
index 692584d..98ac6f6 100644
--- a/core/java/android/credentials/ui/UiResult.java
+++ b/core/java/android/service/autofill/ConvertCredentialResponse.aidl
@@ -1,11 +1,11 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
+/**
+ * Copyright (c) 2024, The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -14,11 +14,6 @@
* limitations under the License.
*/
-package android.credentials.ui;
+package android.service.autofill;
-/**
- * Base class for different types of ui results.
- *
- * @hide
- */
-public interface UiResult {}
+parcelable ConvertCredentialResponse;
\ No newline at end of file
diff --git a/core/java/android/service/autofill/ConvertCredentialResponse.java b/core/java/android/service/autofill/ConvertCredentialResponse.java
new file mode 100644
index 0000000..5da4f63
--- /dev/null
+++ b/core/java/android/service/autofill/ConvertCredentialResponse.java
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.autofill;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.util.DataClass;
+
+/**
+ * Response for a {@Link ConvertCredentialRequest}
+ *
+ * @hide
+ */
+@DataClass(
+ genToString = true,
+ genHiddenConstructor = true,
+ genHiddenConstDefs = true)
+public final class ConvertCredentialResponse implements Parcelable {
+ private final @NonNull Dataset mDataset;
+ private final @Nullable Bundle mClientState;
+
+
+
+
+ // Code below generated by codegen v1.0.23.
+ //
+ // DO NOT MODIFY!
+ // CHECKSTYLE:OFF Generated code
+ //
+ // To regenerate run:
+ // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/service/autofill/ConvertCredentialResponse.java
+ //
+ // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+ // Settings > Editor > Code Style > Formatter Control
+ //@formatter:off
+
+
+ /**
+ * Creates a new ConvertCredentialResponse.
+ *
+ * @hide
+ */
+ @DataClass.Generated.Member
+ public ConvertCredentialResponse(
+ @NonNull Dataset dataset,
+ @Nullable Bundle clientState) {
+ this.mDataset = dataset;
+ com.android.internal.util.AnnotationValidations.validate(
+ NonNull.class, null, mDataset);
+ this.mClientState = clientState;
+
+ // onConstructed(); // You can define this method to get a callback
+ }
+
+ @DataClass.Generated.Member
+ public @NonNull Dataset getDataset() {
+ return mDataset;
+ }
+
+ @DataClass.Generated.Member
+ public @Nullable Bundle getClientState() {
+ return mClientState;
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public String toString() {
+ // You can override field toString logic by defining methods like:
+ // String fieldNameToString() { ... }
+
+ return "ConvertCredentialResponse { " +
+ "dataset = " + mDataset + ", " +
+ "clientState = " + mClientState +
+ " }";
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ // You can override field parcelling by defining methods like:
+ // void parcelFieldName(Parcel dest, int flags) { ... }
+
+ byte flg = 0;
+ if (mClientState != null) flg |= 0x2;
+ dest.writeByte(flg);
+ dest.writeTypedObject(mDataset, flags);
+ if (mClientState != null) dest.writeBundle(mClientState);
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public int describeContents() { return 0; }
+
+ /** @hide */
+ @SuppressWarnings({"unchecked", "RedundantCast"})
+ @DataClass.Generated.Member
+ /* package-private */ ConvertCredentialResponse(@NonNull Parcel in) {
+ // You can override field unparcelling by defining methods like:
+ // static FieldType unparcelFieldName(Parcel in) { ... }
+
+ byte flg = in.readByte();
+ Dataset dataset = (Dataset) in.readTypedObject(Dataset.CREATOR);
+ Bundle clientState = (flg & 0x2) == 0 ? null : in.readBundle();
+
+ this.mDataset = dataset;
+ com.android.internal.util.AnnotationValidations.validate(
+ NonNull.class, null, mDataset);
+ this.mClientState = clientState;
+
+ // onConstructed(); // You can define this method to get a callback
+ }
+
+ @DataClass.Generated.Member
+ public static final @NonNull Parcelable.Creator<ConvertCredentialResponse> CREATOR
+ = new Parcelable.Creator<ConvertCredentialResponse>() {
+ @Override
+ public ConvertCredentialResponse[] newArray(int size) {
+ return new ConvertCredentialResponse[size];
+ }
+
+ @Override
+ public ConvertCredentialResponse createFromParcel(@NonNull Parcel in) {
+ return new ConvertCredentialResponse(in);
+ }
+ };
+
+ @DataClass.Generated(
+ time = 1706132669373L,
+ codegenVersion = "1.0.23",
+ sourceFile = "frameworks/base/core/java/android/service/autofill/ConvertCredentialResponse.java",
+ inputSignatures = "private final @android.annotation.NonNull android.service.autofill.Dataset mDataset\nprivate final @android.annotation.Nullable android.os.Bundle mClientState\nclass ConvertCredentialResponse extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genHiddenConstructor=true, genHiddenConstDefs=true)")
+ @Deprecated
+ private void __metadata() {}
+
+
+ //@formatter:on
+ // End of generated code
+
+}
diff --git a/core/java/android/service/autofill/FillEventHistory.java b/core/java/android/service/autofill/FillEventHistory.java
index 5d58120..98dda10 100644
--- a/core/java/android/service/autofill/FillEventHistory.java
+++ b/core/java/android/service/autofill/FillEventHistory.java
@@ -309,12 +309,19 @@
/** The autofill suggestion is shown as a dialog presentation. */
public static final int UI_TYPE_DIALOG = 3;
+ /**
+ * The autofill suggestion is shown os a credman bottom sheet
+ * @hide
+ */
+ public static final int UI_TYPE_CREDMAN_BOTTOM_SHEET = 4;
+
/** @hide */
@IntDef(prefix = { "UI_TYPE_" }, value = {
UI_TYPE_UNKNOWN,
UI_TYPE_MENU,
UI_TYPE_INLINE,
- UI_TYPE_DIALOG
+ UI_TYPE_DIALOG,
+ UI_TYPE_CREDMAN_BOTTOM_SHEET
})
@Retention(RetentionPolicy.SOURCE)
public @interface UiType {}
@@ -755,6 +762,8 @@
return "UI_TYPE_INLINE";
case UI_TYPE_DIALOG:
return "UI_TYPE_FILL_DIALOG";
+ case UI_TYPE_CREDMAN_BOTTOM_SHEET:
+ return "UI_TYPE_CREDMAN_BOTTOM_SHEET";
default:
return "UI_TYPE_UNKNOWN";
}
diff --git a/core/java/android/service/autofill/IAutoFillService.aidl b/core/java/android/service/autofill/IAutoFillService.aidl
index 03ead32..2c2feae 100644
--- a/core/java/android/service/autofill/IAutoFillService.aidl
+++ b/core/java/android/service/autofill/IAutoFillService.aidl
@@ -16,6 +16,8 @@
package android.service.autofill;
+import android.service.autofill.ConvertCredentialRequest;
+import android.service.autofill.IConvertCredentialCallback;
import android.service.autofill.FillRequest;
import android.service.autofill.IFillCallback;
import android.service.autofill.ISaveCallback;
@@ -32,7 +34,8 @@
void onConnectedStateChanged(boolean connected);
void onFillRequest(in FillRequest request, in IFillCallback callback);
void onFillCredentialRequest(in FillRequest request, in IFillCallback callback,
- in IAutoFillManagerClient client);
+ in IAutoFillManagerClient client);
void onSaveRequest(in SaveRequest request, in ISaveCallback callback);
void onSavedPasswordCountRequest(in IResultReceiver receiver);
+ void onConvertCredentialRequest(in ConvertCredentialRequest convertCredentialRequest, in IConvertCredentialCallback convertCredentialCallback);
}
diff --git a/core/java/android/credentials/ui/UiResult.java b/core/java/android/service/autofill/IConvertCredentialCallback.aidl
similarity index 63%
copy from core/java/android/credentials/ui/UiResult.java
copy to core/java/android/service/autofill/IConvertCredentialCallback.aidl
index 692584d..9dfc294 100644
--- a/core/java/android/credentials/ui/UiResult.java
+++ b/core/java/android/service/autofill/IConvertCredentialCallback.aidl
@@ -14,11 +14,18 @@
* limitations under the License.
*/
-package android.credentials.ui;
+package android.service.autofill;
+
+import android.os.ICancellationSignal;
+
+import android.service.autofill.ConvertCredentialResponse;
/**
- * Base class for different types of ui results.
+ * Interface to receive the result of a convert credential request
*
* @hide
*/
-public interface UiResult {}
+oneway interface IConvertCredentialCallback {
+ void onSuccess(in ConvertCredentialResponse convertCredentialResponse);
+ void onFailure(CharSequence message);
+}
diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java
index 9d19ef6..d4a5356 100644
--- a/core/java/android/service/notification/ZenModeConfig.java
+++ b/core/java/android/service/notification/ZenModeConfig.java
@@ -2297,6 +2297,18 @@
component, configurationActivity, pkg, id, enabler, zenPolicy, modified);
}
+ /** Returns a deep copy of the {@link ZenRule}. */
+ public ZenRule copy() {
+ final Parcel parcel = Parcel.obtain();
+ try {
+ writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ return new ZenRule(parcel);
+ } finally {
+ parcel.recycle();
+ }
+ }
+
public boolean isAutomaticActive() {
return enabled && !snoozing && getPkg() != null && isTrueOrUnknown();
}
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index 2105420b..99bd2ff 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -30,6 +30,7 @@
import android.graphics.text.LineBreakConfig;
import android.graphics.text.LineBreaker;
import android.os.Build;
+import android.os.Trace;
import android.text.style.LeadingMarginSpan;
import android.text.style.LeadingMarginSpan.LeadingMarginSpan2;
import android.text.style.LineHeightSpan;
@@ -534,7 +535,12 @@
if (recycle == null) {
recycle = new StaticLayout();
}
- recycle.generate(this, mIncludePad, trackpadding);
+ Trace.beginSection("Generating StaticLayout For DynamicLayout");
+ try {
+ recycle.generate(this, mIncludePad, trackpadding);
+ } finally {
+ Trace.endSection();
+ }
return recycle;
}
@@ -689,7 +695,12 @@
mLeftIndents = b.mLeftIndents;
mRightIndents = b.mRightIndents;
- generate(b, b.mIncludePad, trackPadding);
+ Trace.beginSection("Constructing StaticLayout");
+ try {
+ generate(b, b.mIncludePad, trackPadding);
+ } finally {
+ Trace.endSection();
+ }
}
private static int getBaseHyphenationFrequency(int frequency) {
diff --git a/core/java/android/view/AttachedSurfaceControl.java b/core/java/android/view/AttachedSurfaceControl.java
index f28574e..27c509a 100644
--- a/core/java/android/view/AttachedSurfaceControl.java
+++ b/core/java/android/view/AttachedSurfaceControl.java
@@ -197,9 +197,28 @@
* Transfer the currently in progress touch gesture from the host to the requested
* {@link SurfaceControlViewHost.SurfacePackage}. This requires that the
* SurfaceControlViewHost was created with the current host's inputToken.
+ * <p>
+ * When the touch is transferred, the window currently receiving touch gets an ACTION_CANCEL
+ * and does not receive any further input events for this gesture.
+ * <p>
+ * The transferred-to window receives an ACTION_DOWN event and then the remainder of the
+ * input events for this gesture. It does not receive any of the previous events of this gesture
+ * that the originating window received.
+ * <p>
+ * The "transferTouch" API only works for the current gesture. When a new gesture arrives,
+ * input dispatcher will do a new round of hit testing. So, if the "host" window is still the
+ * first thing that's being touched, then it will receive the new gesture again. It will
+ * again be up to the host to transfer this new gesture to the embedded.
+ * <p>
+ * Once the transferred-to window receives the gesture, it can choose to give up this gesture
+ * and send it to another window that it's linked to (it can't be an arbitrary window for
+ * security reasons) using the same transferTouch API. Only the window currently receiving
+ * touch is allowed to transfer the gesture.
*
* @param surfacePackage The SurfacePackage to transfer the gesture to.
* @return Whether the touch stream was transferred.
+ * @see SurfaceControlViewHost#transferTouchGestureToHost() for the reverse to transfer touch
+ * gesture from the embedded to the host.
*/
@FlaggedApi(Flags.FLAG_TRANSFER_GESTURE_TO_EMBEDDED)
default boolean transferHostTouchGestureToEmbedded(
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index a1f44e4..6c6e8b2 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -1073,8 +1073,7 @@
if (error == -EINVAL) {
throw new IllegalArgumentException("Invalid argument to Surface.setFrameRate()");
} else if (error != 0) {
- throw new RuntimeException("Failed to set frame rate on Surface. Native error: "
- + error);
+ Log.e(TAG, "Failed to set frame rate on Surface. Native error: " + error);
}
}
}
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 42355bb..427d053 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -6022,8 +6022,8 @@
* This is different from
* {@link #registerUnbatchedSurfaceControlInputReceiver(int, IBinder, SurfaceControl, Looper,
* SurfaceControlInputReceiver)} in that the input events are received batched. The caller must
- * invoke {@link #unregisterSurfaceControlInputReceiver(IBinder)} to clean up the resources when
- * no longer needing to use the {@link SurfaceControlInputReceiver}
+ * invoke {@link #unregisterSurfaceControlInputReceiver(SurfaceControl)} to clean up the
+ * resources when no longer needing to use the {@link SurfaceControlInputReceiver}
*
* @param displayId The display that the SurfaceControl will be placed on. Input will
* only work
@@ -6035,14 +6035,9 @@
* @param choreographer The Choreographer used for batching. This should match the rendering
* Choreographer.
* @param receiver The SurfaceControlInputReceiver that will receive the input events
- * @return an {@link IBinder} token that is used to unregister the input receiver via
- * {@link #unregisterSurfaceControlInputReceiver(IBinder)}.
- * @see #registerUnbatchedSurfaceControlInputReceiver(int, IBinder, SurfaceControl, Looper,
- * SurfaceControlInputReceiver)
*/
@FlaggedApi(Flags.FLAG_SURFACE_CONTROL_INPUT_RECEIVER)
- @NonNull
- default IBinder registerBatchedSurfaceControlInputReceiver(int displayId,
+ default void registerBatchedSurfaceControlInputReceiver(int displayId,
@NonNull IBinder hostToken, @NonNull SurfaceControl surfaceControl,
@NonNull Choreographer choreographer, @NonNull SurfaceControlInputReceiver receiver) {
throw new UnsupportedOperationException(
@@ -6054,8 +6049,8 @@
* receive every input event. This is different than calling @link
* #registerBatchedSurfaceControlInputReceiver(int, IBinder, SurfaceControl, Choreographer,
* SurfaceControlInputReceiver)} in that the input events are received unbatched. The caller
- * must invoke {@link #unregisterSurfaceControlInputReceiver(IBinder)} to clean up the resources
- * when no longer needing to use the {@link SurfaceControlInputReceiver}
+ * must invoke {@link #unregisterSurfaceControlInputReceiver(SurfaceControl)} to clean up the
+ * resources when no longer needing to use the {@link SurfaceControlInputReceiver}
*
* @param displayId The display that the SurfaceControl will be placed on. Input will only
* work if SurfaceControl is on that display and that display was
@@ -6066,14 +6061,9 @@
* @param surfaceControl The SurfaceControl to register the InputChannel for
* @param looper The looper to use when invoking callbacks.
* @param receiver The SurfaceControlInputReceiver that will receive the input events
- * @return an {@link IBinder} token that is used to unregister the input receiver via
- * {@link #unregisterSurfaceControlInputReceiver(IBinder)}.
- * @see #registerBatchedSurfaceControlInputReceiver(int, IBinder, SurfaceControl, Choreographer,
- * SurfaceControlInputReceiver)
**/
@FlaggedApi(Flags.FLAG_SURFACE_CONTROL_INPUT_RECEIVER)
- @NonNull
- default IBinder registerUnbatchedSurfaceControlInputReceiver(int displayId,
+ default void registerUnbatchedSurfaceControlInputReceiver(int displayId,
@NonNull IBinder hostToken, @NonNull SurfaceControl surfaceControl,
@NonNull Looper looper, @NonNull SurfaceControlInputReceiver receiver) {
throw new UnsupportedOperationException(
@@ -6091,17 +6081,32 @@
* {@link #registerUnbatchedSurfaceControlInputReceiver(int, IBinder, SurfaceControl, Looper,
* SurfaceControlInputReceiver)}
*
- * @param token The token that was returned via
- * {@link #registerBatchedSurfaceControlInputReceiver(int, IBinder,
- * SurfaceControl,
- * Choreographer, SurfaceControlInputReceiver)} or
- * {@link #registerUnbatchedSurfaceControlInputReceiver(int, IBinder,
- * SurfaceControl,
- * Looper, SurfaceControlInputReceiver)}
+ * @param surfaceControl The SurfaceControl to remove and unregister the input channel for.
*/
@FlaggedApi(Flags.FLAG_SURFACE_CONTROL_INPUT_RECEIVER)
- default void unregisterSurfaceControlInputReceiver(@NonNull IBinder token) {
+ default void unregisterSurfaceControlInputReceiver(@NonNull SurfaceControl surfaceControl) {
throw new UnsupportedOperationException(
"unregisterSurfaceControlInputReceiver is not implemented");
}
+
+ /**
+ * Returns the input client token for the {@link SurfaceControl}. This will only return non null
+ * if the SurfaceControl was registered for input via
+ * { #registerBatchedSurfaceControlInputReceiver(int, IBinder, SurfaceControl, Choreographer,
+ * SurfaceControlInputReceiver)} or
+ * {@link #registerUnbatchedSurfaceControlInputReceiver(int, IBinder, SurfaceControl, Looper,
+ * SurfaceControlInputReceiver)}.
+ * <p>
+ * This is helpful for testing to ensure the test waits for the layer to be registered with
+ * SurfaceFlinger and Input before proceeding with the test.
+ *
+ * @hide
+ */
+ @FlaggedApi(Flags.FLAG_SURFACE_CONTROL_INPUT_RECEIVER)
+ @TestApi
+ @Nullable
+ default IBinder getSurfaceControlInputClientToken(@NonNull SurfaceControl surfaceControl) {
+ throw new UnsupportedOperationException(
+ "getSurfaceControlInputClientToken is not implemented");
+ }
}
diff --git a/core/java/android/view/WindowManagerGlobal.java b/core/java/android/view/WindowManagerGlobal.java
index 8d40f9a..c49fce5 100644
--- a/core/java/android/view/WindowManagerGlobal.java
+++ b/core/java/android/view/WindowManagerGlobal.java
@@ -38,10 +38,12 @@
import android.util.ArraySet;
import android.util.Log;
import android.util.Pair;
+import android.util.SparseArray;
import android.view.inputmethod.InputMethodManager;
import android.window.ITrustedPresentationListener;
import android.window.TrustedPresentationThresholds;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.FastPrintWriter;
import java.io.FileDescriptor;
@@ -50,7 +52,6 @@
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.WeakHashMap;
-import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;
import java.util.function.Consumer;
import java.util.function.IntConsumer;
@@ -156,8 +157,9 @@
private final TrustedPresentationListener mTrustedPresentationListener =
new TrustedPresentationListener();
- private final ConcurrentHashMap<IBinder, InputEventReceiver> mSurfaceControlInputReceivers =
- new ConcurrentHashMap<>();
+ @GuardedBy("mSurfaceControlInputReceivers")
+ private final SparseArray<SurfaceControlInputReceiverInfo>
+ mSurfaceControlInputReceivers = new SparseArray<>();
private WindowManagerGlobal() {
}
@@ -816,7 +818,7 @@
mTrustedPresentationListener.removeListener(listener);
}
- IBinder registerBatchedSurfaceControlInputReceiver(int displayId,
+ void registerBatchedSurfaceControlInputReceiver(int displayId,
@NonNull IBinder hostToken, @NonNull SurfaceControl surfaceControl,
@NonNull Choreographer choreographer, @NonNull SurfaceControlInputReceiver receiver) {
IBinder clientToken = new Binder();
@@ -830,19 +832,21 @@
e.rethrowAsRuntimeException();
}
- mSurfaceControlInputReceivers.put(clientToken,
- new BatchedInputEventReceiver(inputChannel, choreographer.getLooper(),
- choreographer) {
- @Override
- public void onInputEvent(InputEvent event) {
- boolean handled = receiver.onInputEvent(event);
- finishInputEvent(event, handled);
- }
- });
- return clientToken;
+ synchronized (mSurfaceControlInputReceivers) {
+ mSurfaceControlInputReceivers.put(surfaceControl.getLayerId(),
+ new SurfaceControlInputReceiverInfo(clientToken,
+ new BatchedInputEventReceiver(inputChannel, choreographer.getLooper(),
+ choreographer) {
+ @Override
+ public void onInputEvent(InputEvent event) {
+ boolean handled = receiver.onInputEvent(event);
+ finishInputEvent(event, handled);
+ }
+ }));
+ }
}
- IBinder registerUnbatchedSurfaceControlInputReceiver(
+ void registerUnbatchedSurfaceControlInputReceiver(
int displayId, @NonNull IBinder hostToken, @NonNull SurfaceControl surfaceControl,
@NonNull Looper looper, @NonNull SurfaceControlInputReceiver receiver) {
IBinder clientToken = new Binder();
@@ -856,32 +860,53 @@
e.rethrowAsRuntimeException();
}
- mSurfaceControlInputReceivers.put(clientToken,
- new InputEventReceiver(inputChannel, looper) {
- @Override
- public void onInputEvent(InputEvent event) {
- boolean handled = receiver.onInputEvent(event);
- finishInputEvent(event, handled);
- }
- });
-
- return clientToken;
+ synchronized (mSurfaceControlInputReceivers) {
+ mSurfaceControlInputReceivers.put(surfaceControl.getLayerId(),
+ new SurfaceControlInputReceiverInfo(clientToken,
+ new InputEventReceiver(inputChannel, looper) {
+ @Override
+ public void onInputEvent(InputEvent event) {
+ boolean handled = receiver.onInputEvent(event);
+ finishInputEvent(event, handled);
+ }
+ }));
+ }
}
- void unregisterSurfaceControlInputReceiver(IBinder token) {
- InputEventReceiver inputEventReceiver = mSurfaceControlInputReceivers.get(token);
- if (inputEventReceiver == null) {
- Log.w(TAG, "No registered input event receiver with token: " + token);
+ void unregisterSurfaceControlInputReceiver(SurfaceControl surfaceControl) {
+ SurfaceControlInputReceiverInfo surfaceControlInputReceiverInfo;
+ synchronized (mSurfaceControlInputReceivers) {
+ surfaceControlInputReceiverInfo = mSurfaceControlInputReceivers.removeReturnOld(
+ surfaceControl.getLayerId());
+ }
+
+ if (surfaceControlInputReceiverInfo == null) {
+ Log.w(TAG, "No registered input event receiver with sc: " + surfaceControl);
return;
}
try {
- WindowManagerGlobal.getWindowSession().remove(token);
+ WindowManagerGlobal.getWindowSession().remove(
+ surfaceControlInputReceiverInfo.mClientToken);
} catch (RemoteException e) {
Log.e(TAG, "Failed to remove input channel", e);
e.rethrowAsRuntimeException();
}
- inputEventReceiver.dispose();
+ surfaceControlInputReceiverInfo.mInputEventReceiver.dispose();
+ }
+
+ IBinder getSurfaceControlInputClientToken(SurfaceControl surfaceControl) {
+ SurfaceControlInputReceiverInfo surfaceControlInputReceiverInfo;
+ synchronized (mSurfaceControlInputReceivers) {
+ surfaceControlInputReceiverInfo = mSurfaceControlInputReceivers.get(
+ surfaceControl.getLayerId());
+ }
+
+ if (surfaceControlInputReceiverInfo == null) {
+ Log.w(TAG, "No registered input event receiver with sc: " + surfaceControl);
+ return null;
+ }
+ return surfaceControlInputReceiverInfo.mClientToken;
}
private final class TrustedPresentationListener extends
@@ -976,6 +1001,17 @@
throw e.rethrowFromSystemServer();
}
}
+
+ private static class SurfaceControlInputReceiverInfo {
+ final IBinder mClientToken;
+ final InputEventReceiver mInputEventReceiver;
+
+ private SurfaceControlInputReceiverInfo(IBinder clientToken,
+ InputEventReceiver inputEventReceiver) {
+ mClientToken = clientToken;
+ mInputEventReceiver = inputEventReceiver;
+ }
+ }
}
final class WindowLeaked extends AndroidRuntimeException {
diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java
index aaf5fcc..41d181c 100644
--- a/core/java/android/view/WindowManagerImpl.java
+++ b/core/java/android/view/WindowManagerImpl.java
@@ -523,26 +523,30 @@
mGlobal.unregisterTrustedPresentationListener(listener);
}
- @NonNull
@Override
- public IBinder registerBatchedSurfaceControlInputReceiver(int displayId,
+ public void registerBatchedSurfaceControlInputReceiver(int displayId,
@NonNull IBinder hostToken, @NonNull SurfaceControl surfaceControl,
@NonNull Choreographer choreographer, @NonNull SurfaceControlInputReceiver receiver) {
- return mGlobal.registerBatchedSurfaceControlInputReceiver(displayId, hostToken,
+ mGlobal.registerBatchedSurfaceControlInputReceiver(displayId, hostToken,
surfaceControl, choreographer, receiver);
}
- @NonNull
@Override
- public IBinder registerUnbatchedSurfaceControlInputReceiver(
+ public void registerUnbatchedSurfaceControlInputReceiver(
int displayId, @NonNull IBinder hostToken, @NonNull SurfaceControl surfaceControl,
@NonNull Looper looper, @NonNull SurfaceControlInputReceiver receiver) {
- return mGlobal.registerUnbatchedSurfaceControlInputReceiver(displayId, hostToken,
+ mGlobal.registerUnbatchedSurfaceControlInputReceiver(displayId, hostToken,
surfaceControl, looper, receiver);
}
@Override
- public void unregisterSurfaceControlInputReceiver(@NonNull IBinder token) {
- mGlobal.unregisterSurfaceControlInputReceiver(token);
+ public void unregisterSurfaceControlInputReceiver(@NonNull SurfaceControl surfaceControl) {
+ mGlobal.unregisterSurfaceControlInputReceiver(surfaceControl);
+ }
+
+ @Override
+ @Nullable
+ public IBinder getSurfaceControlInputClientToken(@NonNull SurfaceControl surfaceControl) {
+ return mGlobal.getSurfaceControlInputClientToken(surfaceControl);
}
}
diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java
index 49d2ceb..7782fd7 100644
--- a/core/java/android/view/accessibility/AccessibilityManager.java
+++ b/core/java/android/view/accessibility/AccessibilityManager.java
@@ -66,6 +66,7 @@
import android.view.accessibility.AccessibilityEvent.EventType;
import com.android.internal.R;
+import com.android.internal.accessibility.common.ShortcutConstants;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.IntPair;
@@ -155,22 +156,6 @@
public static final String ACTION_CHOOSE_ACCESSIBILITY_BUTTON =
"com.android.internal.intent.action.CHOOSE_ACCESSIBILITY_BUTTON";
- /**
- * Used as an int value for accessibility chooser activity to represent the accessibility button
- * shortcut type.
- *
- * @hide
- */
- public static final int ACCESSIBILITY_BUTTON = 0;
-
- /**
- * Used as an int value for accessibility chooser activity to represent hardware key shortcut,
- * such as volume key button.
- *
- * @hide
- */
- public static final int ACCESSIBILITY_SHORTCUT_KEY = 1;
-
/** @hide */
public static final int FLASH_REASON_CALL = 1;
@@ -184,32 +169,6 @@
public static final int FLASH_REASON_PREVIEW = 4;
/**
- * Annotations for the shortcut type.
- * <p>Note: Keep in sync with {@link #SHORTCUT_TYPES}.</p>
- * @hide
- */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(value = {
- // LINT.IfChange(shortcut_type_intdef)
- ACCESSIBILITY_BUTTON,
- ACCESSIBILITY_SHORTCUT_KEY
- // LINT.ThenChange(:shortcut_type_array)
- })
- public @interface ShortcutType {}
-
- /**
- * Used for iterating through {@link ShortcutType}.
- * <p>Note: Keep in sync with {@link ShortcutType}.</p>
- * @hide
- */
- public static final int[] SHORTCUT_TYPES = {
- // LINT.IfChange(shortcut_type_array)
- ACCESSIBILITY_BUTTON,
- ACCESSIBILITY_SHORTCUT_KEY,
- // LINT.ThenChange(:shortcut_type_intdef)
- };
-
- /**
* Annotations for content flag of UI.
* @hide
*/
@@ -1785,7 +1744,8 @@
@TestApi
@RequiresPermission(Manifest.permission.MANAGE_ACCESSIBILITY)
@NonNull
- public List<String> getAccessibilityShortcutTargets(@ShortcutType int shortcutType) {
+ public List<String> getAccessibilityShortcutTargets(
+ @ShortcutConstants.UserShortcutType int shortcutType) {
final IAccessibilityManager service;
synchronized (mLock) {
service = getServiceLocked();
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index dbeffc8..559ccfea7 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -298,6 +298,15 @@
"android.view.autofill.extra.AUGMENTED_AUTOFILL_CLIENT";
/**
+ * Internal extra used to pass the fill request id in client state of
+ * {@link ConvertCredentialResponse}
+ *
+ * @hide
+ */
+ public static final String EXTRA_AUTOFILL_REQUEST_ID =
+ "android.view.autofill.extra.AUTOFILL_REQUEST_ID";
+
+ /**
* Autofill Hint to indicate that it can match any field.
*
* @hide
diff --git a/core/java/android/view/contentprotection/flags/content_protection_flags.aconfig b/core/java/android/view/contentprotection/flags/content_protection_flags.aconfig
index 2a3008a..5d3153c 100644
--- a/core/java/android/view/contentprotection/flags/content_protection_flags.aconfig
+++ b/core/java/android/view/contentprotection/flags/content_protection_flags.aconfig
@@ -34,3 +34,10 @@
description: "If true, an appop is logged when a notification is rapidly cleared by a notification listener."
bug: "289080543"
}
+
+flag {
+ name: "manage_device_policy_enabled"
+ namespace: "content_protection"
+ description: "If true, the APIs to manage content protection device policy will be enabled."
+ bug: "319477846"
+}
diff --git a/core/java/android/window/ScreenCapture.java b/core/java/android/window/ScreenCapture.java
index befb002..5446428 100644
--- a/core/java/android/window/ScreenCapture.java
+++ b/core/java/android/window/ScreenCapture.java
@@ -30,6 +30,8 @@
import android.util.Log;
import android.view.SurfaceControl;
+import com.android.window.flags.Flags;
+
import libcore.util.NativeAllocationRegistry;
import java.util.concurrent.CountDownLatch;
@@ -48,7 +50,7 @@
private static native int nativeCaptureDisplay(DisplayCaptureArgs captureArgs,
long captureListener);
private static native int nativeCaptureLayers(LayerCaptureArgs captureArgs,
- long captureListener);
+ long captureListener, boolean sync);
private static native long nativeCreateScreenCaptureListener(
ObjIntConsumer<ScreenshotHardwareBuffer> consumer);
private static native void nativeWriteListenerToParcel(long nativeObject, Parcel out);
@@ -134,7 +136,8 @@
*/
public static ScreenshotHardwareBuffer captureLayers(LayerCaptureArgs captureArgs) {
SynchronousScreenCaptureListener syncScreenCapture = createSyncCaptureListener();
- int status = captureLayers(captureArgs, syncScreenCapture);
+ int status = nativeCaptureLayers(captureArgs, syncScreenCapture.mNativeObject,
+ Flags.syncScreenCapture());
if (status != 0) {
return null;
}
@@ -171,7 +174,7 @@
*/
public static int captureLayers(@NonNull LayerCaptureArgs captureArgs,
@NonNull ScreenCaptureListener captureListener) {
- return nativeCaptureLayers(captureArgs, captureListener.mNativeObject);
+ return nativeCaptureLayers(captureArgs, captureListener.mNativeObject, false /* sync */);
}
/**
@@ -674,7 +677,7 @@
* This listener can only be used for a single call to capture content call.
*/
public static class ScreenCaptureListener implements Parcelable {
- private final long mNativeObject;
+ final long mNativeObject;
private static final NativeAllocationRegistry sRegistry =
NativeAllocationRegistry.createMalloced(
ScreenCaptureListener.class.getClassLoader(), getNativeListenerFinalizer());
diff --git a/core/java/android/window/WindowOnBackInvokedDispatcher.java b/core/java/android/window/WindowOnBackInvokedDispatcher.java
index 86804c6..65075ae 100644
--- a/core/java/android/window/WindowOnBackInvokedDispatcher.java
+++ b/core/java/android/window/WindowOnBackInvokedDispatcher.java
@@ -226,9 +226,6 @@
setTopOnBackInvokedCallback(null);
}
- // We should also stop running animations since all callbacks have been removed.
- // note: mSpring.skipToEnd(), in ProgressAnimator.reset(), requires the main handler.
- Handler.getMain().post(mProgressAnimator::reset);
mAllCallbacks.clear();
mOnBackInvokedCallbacks.clear();
}
@@ -442,8 +439,7 @@
return WindowOnBackInvokedDispatcher
.isOnBackInvokedCallbackEnabled(activityInfo, applicationInfo,
- () -> originalContext.obtainStyledAttributes(
- new int[] {android.R.attr.windowSwipeToDismiss}), true);
+ () -> originalContext);
}
@Override
@@ -501,7 +497,7 @@
*/
public static boolean isOnBackInvokedCallbackEnabled(@Nullable ActivityInfo activityInfo,
@NonNull ApplicationInfo applicationInfo,
- @NonNull Supplier<TypedArray> windowAttrSupplier, boolean recycleTypedArray) {
+ @NonNull Supplier<Context> contextSupplier) {
// new back is enabled if the feature flag is enabled AND the app does not explicitly
// request legacy back.
if (!ENABLE_PREDICTIVE_BACK) {
@@ -547,15 +543,15 @@
// setTrigger(true)
// Use the original context to resolve the styled attribute so that they stay
// true to the window.
- TypedArray windowAttr = windowAttrSupplier.get();
+ final Context context = contextSupplier.get();
boolean windowSwipeToDismiss = true;
- if (windowAttr != null) {
- if (windowAttr.getIndexCount() > 0) {
- windowSwipeToDismiss = windowAttr.getBoolean(0, true);
+ if (context != null) {
+ final TypedArray array = context.obtainStyledAttributes(
+ new int[]{android.R.attr.windowSwipeToDismiss});
+ if (array.getIndexCount() > 0) {
+ windowSwipeToDismiss = array.getBoolean(0, true);
}
- if (recycleTypedArray) {
- windowAttr.recycle();
- }
+ array.recycle();
}
if (DEBUG) {
diff --git a/core/java/android/window/flags/window_surfaces.aconfig b/core/java/android/window/flags/window_surfaces.aconfig
index 751c1a8..069affb 100644
--- a/core/java/android/window/flags/window_surfaces.aconfig
+++ b/core/java/android/window/flags/window_surfaces.aconfig
@@ -88,3 +88,11 @@
is_fixed_read_only: true
bug: "304574518"
}
+
+flag {
+ namespace: "window_surfaces"
+ name: "sync_screen_capture"
+ description: "Create a screen capture API that blocks in SurfaceFlinger"
+ is_fixed_read_only: true
+ bug: "321263247"
+}
diff --git a/core/java/android/window/flags/windowing_sdk.aconfig b/core/java/android/window/flags/windowing_sdk.aconfig
index 6e5807b..4a6e8d7 100644
--- a/core/java/android/window/flags/windowing_sdk.aconfig
+++ b/core/java/android/window/flags/windowing_sdk.aconfig
@@ -42,6 +42,14 @@
flag {
namespace: "windowing_sdk"
+ name: "untrusted_embedding_any_app_permission"
+ description: "Feature flag to enable the permission to embed any app in untrusted mode."
+ bug: "289199433"
+ is_fixed_read_only: true
+}
+
+flag {
+ namespace: "windowing_sdk"
name: "activity_window_info_flag"
description: "To dispatch ActivityWindowInfo through ClientTransaction"
bug: "287582673"
diff --git a/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java b/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java
index de0f070..b4395a7 100644
--- a/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java
+++ b/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java
@@ -18,7 +18,6 @@
import static android.accessibilityservice.AccessibilityServiceInfo.FEEDBACK_ALL_MASK;
import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG;
-import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_SHORTCUT_KEY;
import static com.android.internal.accessibility.dialog.AccessibilityTargetHelper.getTargets;
import static com.android.internal.os.RoSystemProperties.SUPPORT_ONE_HANDED_MODE;
@@ -329,7 +328,8 @@
}
private AlertDialog createShortcutWarningDialog(int userId) {
- List<AccessibilityTarget> targets = getTargets(mContext, ACCESSIBILITY_SHORTCUT_KEY);
+ List<AccessibilityTarget> targets = getTargets(mContext,
+ ShortcutConstants.UserShortcutType.HARDWARE);
if (targets.size() == 0) {
return null;
}
@@ -541,7 +541,7 @@
private ComponentName getShortcutTargetComponentName() {
final List<String> shortcutTargets = mFrameworkObjectProvider
.getAccessibilityManagerInstance(mContext)
- .getAccessibilityShortcutTargets(ACCESSIBILITY_SHORTCUT_KEY);
+ .getAccessibilityShortcutTargets(ShortcutConstants.UserShortcutType.HARDWARE);
if (shortcutTargets.size() != 1) {
return null;
}
diff --git a/core/java/com/android/internal/accessibility/common/ShortcutConstants.java b/core/java/com/android/internal/accessibility/common/ShortcutConstants.java
index 7ec8838..353e182 100644
--- a/core/java/com/android/internal/accessibility/common/ShortcutConstants.java
+++ b/core/java/com/android/internal/accessibility/common/ShortcutConstants.java
@@ -44,19 +44,27 @@
* choose accessibility shortcut as preferred shortcut.
* {@code TRIPLETAP} for displaying specifying magnification to be toggled via quickly
* tapping screen 3 times as preferred shortcut.
+ * {@code TWO_FINGERS_TRIPLE_TAP} for displaying specifying magnification to be toggled via
+ * quickly tapping screen 3 times with two fingers as preferred shortcut.
*/
@Retention(RetentionPolicy.SOURCE)
- @IntDef({
- UserShortcutType.DEFAULT,
- UserShortcutType.SOFTWARE,
- UserShortcutType.HARDWARE,
- UserShortcutType.TRIPLETAP,
- })
+ @IntDef(
+ flag = true,
+ value = {
+ UserShortcutType.DEFAULT,
+ UserShortcutType.SOFTWARE,
+ UserShortcutType.HARDWARE,
+ UserShortcutType.TRIPLETAP,
+ UserShortcutType.TWO_FINGERS_TRIPLE_TAP,
+ })
public @interface UserShortcutType {
int DEFAULT = 0;
- int SOFTWARE = 1; // 1 << 0
- int HARDWARE = 2; // 1 << 1
- int TRIPLETAP = 4; // 1 << 2
+ // LINT.IfChange(shortcut_type_intdef)
+ int SOFTWARE = 1;
+ int HARDWARE = 1 << 1;
+ int TRIPLETAP = 1 << 2;
+ int TWO_FINGERS_TRIPLE_TAP = 1 << 3;
+ // LINT.ThenChange(:shortcut_type_array)
}
/**
@@ -64,9 +72,12 @@
* non-default IntDef types.
*/
public static final int[] USER_SHORTCUT_TYPES = {
+ // LINT.IfChange(shortcut_type_array)
UserShortcutType.SOFTWARE,
UserShortcutType.HARDWARE,
- UserShortcutType.TRIPLETAP
+ UserShortcutType.TRIPLETAP,
+ UserShortcutType.TWO_FINGERS_TRIPLE_TAP,
+ // LINT.ThenChange(:shortcut_type_intdef)
};
diff --git a/core/java/com/android/internal/accessibility/dialog/AccessibilityActivityTarget.java b/core/java/com/android/internal/accessibility/dialog/AccessibilityActivityTarget.java
index 063154d..33048dc 100644
--- a/core/java/com/android/internal/accessibility/dialog/AccessibilityActivityTarget.java
+++ b/core/java/com/android/internal/accessibility/dialog/AccessibilityActivityTarget.java
@@ -17,14 +17,13 @@
package com.android.internal.accessibility.dialog;
import static com.android.internal.accessibility.util.ShortcutUtils.convertToKey;
-import static com.android.internal.accessibility.util.ShortcutUtils.convertToUserType;
import static com.android.internal.accessibility.util.ShortcutUtils.isShortcutContained;
import android.accessibilityservice.AccessibilityShortcutInfo;
import android.annotation.NonNull;
import android.content.Context;
-import android.view.accessibility.AccessibilityManager.ShortcutType;
+import com.android.internal.accessibility.common.ShortcutConstants;
import com.android.internal.accessibility.common.ShortcutConstants.AccessibilityFragmentType;
import com.android.internal.accessibility.common.ShortcutConstants.ShortcutMenuMode;
@@ -33,7 +32,8 @@
*/
class AccessibilityActivityTarget extends AccessibilityTarget {
- AccessibilityActivityTarget(Context context, @ShortcutType int shortcutType,
+ AccessibilityActivityTarget(Context context,
+ @ShortcutConstants.UserShortcutType int shortcutType,
@NonNull AccessibilityShortcutInfo shortcutInfo) {
super(context,
shortcutType,
@@ -44,7 +44,7 @@
shortcutInfo.getActivityInfo().applicationInfo.uid,
shortcutInfo.getActivityInfo().loadLabel(context.getPackageManager()),
shortcutInfo.getActivityInfo().loadIcon(context.getPackageManager()),
- convertToKey(convertToUserType(shortcutType)));
+ convertToKey(shortcutType));
}
@Override
diff --git a/core/java/com/android/internal/accessibility/dialog/AccessibilityButtonChooserActivity.java b/core/java/com/android/internal/accessibility/dialog/AccessibilityButtonChooserActivity.java
index 7eb09e5..e084ebd 100644
--- a/core/java/com/android/internal/accessibility/dialog/AccessibilityButtonChooserActivity.java
+++ b/core/java/com/android/internal/accessibility/dialog/AccessibilityButtonChooserActivity.java
@@ -17,7 +17,6 @@
package com.android.internal.accessibility.dialog;
import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL;
-import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_BUTTON;
import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_COMPONENT_NAME;
import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_CONTROLLER_NAME;
@@ -36,6 +35,7 @@
import android.widget.TextView;
import com.android.internal.R;
+import com.android.internal.accessibility.common.ShortcutConstants;
import com.android.internal.widget.ResolverDrawerLayout;
import java.util.ArrayList;
@@ -85,7 +85,7 @@
prompt.setVisibility(View.VISIBLE);
}
- mTargets.addAll(getTargets(this, ACCESSIBILITY_BUTTON));
+ mTargets.addAll(getTargets(this, ShortcutConstants.UserShortcutType.SOFTWARE));
final GridView gridview = findViewById(R.id.accessibility_button_chooser_grid);
gridview.setAdapter(new ButtonTargetAdapter(mTargets));
diff --git a/core/java/com/android/internal/accessibility/dialog/AccessibilityServiceTarget.java b/core/java/com/android/internal/accessibility/dialog/AccessibilityServiceTarget.java
index 2b6913c..7406da4 100644
--- a/core/java/com/android/internal/accessibility/dialog/AccessibilityServiceTarget.java
+++ b/core/java/com/android/internal/accessibility/dialog/AccessibilityServiceTarget.java
@@ -17,14 +17,13 @@
package com.android.internal.accessibility.dialog;
import static com.android.internal.accessibility.util.ShortcutUtils.convertToKey;
-import static com.android.internal.accessibility.util.ShortcutUtils.convertToUserType;
import static com.android.internal.accessibility.util.ShortcutUtils.isShortcutContained;
import android.accessibilityservice.AccessibilityServiceInfo;
import android.annotation.NonNull;
import android.content.Context;
-import android.view.accessibility.AccessibilityManager.ShortcutType;
+import com.android.internal.accessibility.common.ShortcutConstants;
import com.android.internal.accessibility.common.ShortcutConstants.AccessibilityFragmentType;
import com.android.internal.accessibility.common.ShortcutConstants.ShortcutMenuMode;
@@ -36,7 +35,9 @@
private final AccessibilityServiceInfo mAccessibilityServiceInfo;
- AccessibilityServiceTarget(Context context, @ShortcutType int shortcutType,
+ AccessibilityServiceTarget(
+ Context context,
+ @ShortcutConstants.UserShortcutType int shortcutType,
@AccessibilityFragmentType int fragmentType,
@NonNull AccessibilityServiceInfo serviceInfo) {
super(context,
@@ -48,7 +49,7 @@
serviceInfo.getResolveInfo().serviceInfo.applicationInfo.uid,
serviceInfo.getResolveInfo().loadLabel(context.getPackageManager()),
serviceInfo.getResolveInfo().loadIcon(context.getPackageManager()),
- convertToKey(convertToUserType(shortcutType)));
+ convertToKey(shortcutType));
mAccessibilityServiceInfo = serviceInfo;
}
diff --git a/core/java/com/android/internal/accessibility/dialog/AccessibilityShortcutChooserActivity.java b/core/java/com/android/internal/accessibility/dialog/AccessibilityShortcutChooserActivity.java
index 2e80b7e..8e2ec1b 100644
--- a/core/java/com/android/internal/accessibility/dialog/AccessibilityShortcutChooserActivity.java
+++ b/core/java/com/android/internal/accessibility/dialog/AccessibilityShortcutChooserActivity.java
@@ -15,10 +15,6 @@
*/
package com.android.internal.accessibility.dialog;
-import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_BUTTON;
-import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_SHORTCUT_KEY;
-import static android.view.accessibility.AccessibilityManager.ShortcutType;
-
import static com.android.internal.accessibility.common.ShortcutConstants.ShortcutMenuMode;
import static com.android.internal.accessibility.dialog.AccessibilityTargetHelper.createEnableDialogContentView;
import static com.android.internal.accessibility.dialog.AccessibilityTargetHelper.getInstalledTargets;
@@ -42,6 +38,7 @@
import android.widget.AdapterView;
import com.android.internal.R;
+import com.android.internal.accessibility.common.ShortcutConstants;
import com.android.internal.annotations.VisibleForTesting;
import java.util.ArrayList;
@@ -52,8 +49,8 @@
* activity or allowlisting feature for volume key shortcut.
*/
public class AccessibilityShortcutChooserActivity extends Activity {
- @ShortcutType
- private final int mShortcutType = ACCESSIBILITY_SHORTCUT_KEY;
+ @ShortcutConstants.UserShortcutType
+ private final int mShortcutType = ShortcutConstants.UserShortcutType.HARDWARE;
private static final String KEY_ACCESSIBILITY_SHORTCUT_MENU_MODE =
"accessibility_shortcut_menu_mode";
private final List<AccessibilityTarget> mTargets = new ArrayList<>();
@@ -246,7 +243,7 @@
mTargetAdapter.getShortcutMenuMode() == ShortcutMenuMode.EDIT;
final int selectDialogTitleId = R.string.accessibility_select_shortcut_menu_title;
final int editDialogTitleId =
- mShortcutType == ACCESSIBILITY_BUTTON
+ mShortcutType == ShortcutConstants.UserShortcutType.SOFTWARE
? R.string.accessibility_edit_shortcut_menu_button_title
: R.string.accessibility_edit_shortcut_menu_volume_title;
diff --git a/core/java/com/android/internal/accessibility/dialog/AccessibilityTarget.java b/core/java/com/android/internal/accessibility/dialog/AccessibilityTarget.java
index 652cb52..4ab1ee9 100644
--- a/core/java/com/android/internal/accessibility/dialog/AccessibilityTarget.java
+++ b/core/java/com/android/internal/accessibility/dialog/AccessibilityTarget.java
@@ -16,10 +16,6 @@
package com.android.internal.accessibility.dialog;
-import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_BUTTON;
-import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_SHORTCUT_KEY;
-
-import static com.android.internal.accessibility.util.ShortcutUtils.convertToUserType;
import static com.android.internal.accessibility.util.ShortcutUtils.optInValueToSettings;
import static com.android.internal.accessibility.util.ShortcutUtils.optOutValueFromSettings;
@@ -30,7 +26,6 @@
import android.graphics.drawable.Drawable;
import android.view.View;
import android.view.accessibility.AccessibilityManager;
-import android.view.accessibility.AccessibilityManager.ShortcutType;
import com.android.internal.accessibility.common.ShortcutConstants;
import com.android.internal.accessibility.common.ShortcutConstants.AccessibilityFragmentType;
@@ -47,7 +42,7 @@
public abstract class AccessibilityTarget implements TargetOperations, OnTargetSelectedListener,
OnTargetCheckedChangeListener {
private Context mContext;
- @ShortcutType
+ @ShortcutConstants.UserShortcutType
private int mShortcutType;
@AccessibilityFragmentType
private int mFragmentType;
@@ -61,7 +56,8 @@
private CharSequence mStateDescription;
@VisibleForTesting
- public AccessibilityTarget(Context context, @ShortcutType int shortcutType,
+ public AccessibilityTarget(
+ Context context, @ShortcutConstants.UserShortcutType int shortcutType,
@AccessibilityFragmentType int fragmentType, boolean isShortcutSwitched, String id,
int uid, CharSequence label, Drawable icon, String key) {
mContext = context;
@@ -99,10 +95,10 @@
final AccessibilityManager am =
getContext().getSystemService(AccessibilityManager.class);
switch (getShortcutType()) {
- case ACCESSIBILITY_BUTTON:
+ case ShortcutConstants.UserShortcutType.SOFTWARE:
am.notifyAccessibilityButtonClicked(getContext().getDisplayId(), getId());
return;
- case ACCESSIBILITY_SHORTCUT_KEY:
+ case ShortcutConstants.UserShortcutType.HARDWARE:
am.performAccessibilityShortcut(getId());
return;
default:
@@ -114,9 +110,9 @@
public void onCheckedChanged(boolean isChecked) {
setShortcutEnabled(isChecked);
if (isChecked) {
- optInValueToSettings(getContext(), convertToUserType(getShortcutType()), getId());
+ optInValueToSettings(getContext(), getShortcutType(), getId());
} else {
- optOutValueFromSettings(getContext(), convertToUserType(getShortcutType()), getId());
+ optOutValueFromSettings(getContext(), getShortcutType(), getId());
}
}
@@ -142,7 +138,7 @@
return mContext;
}
- public @ShortcutType int getShortcutType() {
+ public @ShortcutConstants.UserShortcutType int getShortcutType() {
return mShortcutType;
}
diff --git a/core/java/com/android/internal/accessibility/dialog/AccessibilityTargetHelper.java b/core/java/com/android/internal/accessibility/dialog/AccessibilityTargetHelper.java
index 51a5ddf..bd63e23 100644
--- a/core/java/com/android/internal/accessibility/dialog/AccessibilityTargetHelper.java
+++ b/core/java/com/android/internal/accessibility/dialog/AccessibilityTargetHelper.java
@@ -16,8 +16,6 @@
package com.android.internal.accessibility.dialog;
-import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_BUTTON;
-
import static com.android.internal.accessibility.AccessibilityShortcutController.ACCESSIBILITY_HEARING_AIDS_COMPONENT_NAME;
import static com.android.internal.accessibility.AccessibilityShortcutController.COLOR_INVERSION_COMPONENT_NAME;
import static com.android.internal.accessibility.AccessibilityShortcutController.DALTONIZER_COMPONENT_NAME;
@@ -41,12 +39,12 @@
import android.view.LayoutInflater;
import android.view.View;
import android.view.accessibility.AccessibilityManager;
-import android.view.accessibility.AccessibilityManager.ShortcutType;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import com.android.internal.R;
+import com.android.internal.accessibility.common.ShortcutConstants;
import com.android.internal.accessibility.common.ShortcutConstants.AccessibilityFragmentType;
import java.util.ArrayList;
@@ -70,8 +68,9 @@
* @return The list of {@link AccessibilityTarget}.
* @hide
*/
- public static List<AccessibilityTarget> getTargets(Context context,
- @ShortcutType int shortcutType) {
+ public static List<AccessibilityTarget> getTargets(
+ Context context,
+ @ShortcutConstants.UserShortcutType int shortcutType) {
// List all accessibility target
final List<AccessibilityTarget> installedTargets = getInstalledTargets(context,
shortcutType);
@@ -113,7 +112,7 @@
* @return The list of {@link AccessibilityTarget}.
*/
static List<AccessibilityTarget> getInstalledTargets(Context context,
- @ShortcutType int shortcutType) {
+ @ShortcutConstants.UserShortcutType int shortcutType) {
final List<AccessibilityTarget> targets = new ArrayList<>();
targets.addAll(getAccessibilityFilteredTargets(context, shortcutType));
targets.addAll(getAllowListingFeatureTargets(context, shortcutType));
@@ -122,7 +121,7 @@
}
private static List<AccessibilityTarget> getAccessibilityFilteredTargets(Context context,
- @ShortcutType int shortcutType) {
+ @ShortcutConstants.UserShortcutType int shortcutType) {
final List<AccessibilityTarget> serviceTargets =
getAccessibilityServiceTargets(context, shortcutType);
final List<AccessibilityTarget> activityTargets =
@@ -155,7 +154,7 @@
}
private static List<AccessibilityTarget> getAccessibilityServiceTargets(Context context,
- @ShortcutType int shortcutType) {
+ @ShortcutConstants.UserShortcutType int shortcutType) {
final AccessibilityManager am = (AccessibilityManager) context.getSystemService(
Context.ACCESSIBILITY_SERVICE);
final List<AccessibilityServiceInfo> installedServices =
@@ -171,7 +170,7 @@
final boolean hasRequestAccessibilityButtonFlag =
(info.flags & AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON) != 0;
if ((targetSdk <= Build.VERSION_CODES.Q) && !hasRequestAccessibilityButtonFlag
- && (shortcutType == ACCESSIBILITY_BUTTON)) {
+ && (shortcutType == ShortcutConstants.UserShortcutType.SOFTWARE)) {
continue;
}
@@ -182,7 +181,7 @@
}
private static List<AccessibilityTarget> getAccessibilityActivityTargets(Context context,
- @ShortcutType int shortcutType) {
+ @ShortcutConstants.UserShortcutType int shortcutType) {
final AccessibilityManager am = (AccessibilityManager) context.getSystemService(
Context.ACCESSIBILITY_SERVICE);
final List<AccessibilityShortcutInfo> installedServices =
@@ -201,7 +200,7 @@
}
private static List<AccessibilityTarget> getAllowListingFeatureTargets(Context context,
- @ShortcutType int shortcutType) {
+ @ShortcutConstants.UserShortcutType int shortcutType) {
final List<AccessibilityTarget> targets = new ArrayList<>();
final int uid = context.getApplicationInfo().uid;
@@ -281,8 +280,10 @@
return targets;
}
- private static AccessibilityTarget createAccessibilityServiceTarget(Context context,
- @ShortcutType int shortcutType, @NonNull AccessibilityServiceInfo info) {
+ private static AccessibilityTarget createAccessibilityServiceTarget(
+ Context context,
+ @ShortcutConstants.UserShortcutType int shortcutType,
+ @NonNull AccessibilityServiceInfo info) {
switch (getAccessibilityServiceFragmentType(info)) {
case AccessibilityFragmentType.VOLUME_SHORTCUT_TOGGLE:
return new VolumeShortcutToggleAccessibilityServiceTarget(context, shortcutType,
diff --git a/core/java/com/android/internal/accessibility/dialog/InvisibleToggleAccessibilityServiceTarget.java b/core/java/com/android/internal/accessibility/dialog/InvisibleToggleAccessibilityServiceTarget.java
index 1bc8b84..641a9f1 100644
--- a/core/java/com/android/internal/accessibility/dialog/InvisibleToggleAccessibilityServiceTarget.java
+++ b/core/java/com/android/internal/accessibility/dialog/InvisibleToggleAccessibilityServiceTarget.java
@@ -16,9 +16,6 @@
package com.android.internal.accessibility.dialog;
-import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_BUTTON;
-import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_SHORTCUT_KEY;
-
import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType;
import static com.android.internal.accessibility.util.AccessibilityUtils.setAccessibilityServiceState;
import static com.android.internal.accessibility.util.ShortcutUtils.isComponentIdExistingInSettings;
@@ -28,7 +25,6 @@
import android.content.ComponentName;
import android.content.Context;
import android.os.UserHandle;
-import android.view.accessibility.AccessibilityManager.ShortcutType;
import android.view.accessibility.Flags;
import com.android.internal.accessibility.common.ShortcutConstants.AccessibilityFragmentType;
@@ -45,7 +41,7 @@
public class InvisibleToggleAccessibilityServiceTarget extends AccessibilityServiceTarget {
public InvisibleToggleAccessibilityServiceTarget(
- Context context, @ShortcutType int shortcutType,
+ Context context, @UserShortcutType int shortcutType,
@NonNull AccessibilityServiceInfo serviceInfo) {
super(context,
shortcutType,
@@ -72,10 +68,10 @@
private boolean isComponentIdExistingInOtherShortcut() {
switch (getShortcutType()) {
- case ACCESSIBILITY_BUTTON:
+ case UserShortcutType.SOFTWARE:
return isComponentIdExistingInSettings(getContext(), UserShortcutType.HARDWARE,
getId());
- case ACCESSIBILITY_SHORTCUT_KEY:
+ case UserShortcutType.HARDWARE:
return isComponentIdExistingInSettings(getContext(), UserShortcutType.SOFTWARE,
getId());
default:
diff --git a/core/java/com/android/internal/accessibility/dialog/InvisibleToggleAllowListingFeatureTarget.java b/core/java/com/android/internal/accessibility/dialog/InvisibleToggleAllowListingFeatureTarget.java
index c22f17d..2204c0b 100644
--- a/core/java/com/android/internal/accessibility/dialog/InvisibleToggleAllowListingFeatureTarget.java
+++ b/core/java/com/android/internal/accessibility/dialog/InvisibleToggleAllowListingFeatureTarget.java
@@ -18,8 +18,8 @@
import android.content.Context;
import android.graphics.drawable.Drawable;
-import android.view.accessibility.AccessibilityManager.ShortcutType;
+import com.android.internal.accessibility.common.ShortcutConstants;
import com.android.internal.accessibility.common.ShortcutConstants.AccessibilityFragmentType;
/**
@@ -28,7 +28,8 @@
*/
class InvisibleToggleAllowListingFeatureTarget extends AccessibilityTarget {
- InvisibleToggleAllowListingFeatureTarget(Context context, @ShortcutType int shortcutType,
+ InvisibleToggleAllowListingFeatureTarget(Context context,
+ @ShortcutConstants.UserShortcutType int shortcutType,
boolean isShortcutSwitched, String id, int uid, CharSequence label, Drawable icon,
String key) {
super(context, shortcutType, AccessibilityFragmentType.INVISIBLE_TOGGLE, isShortcutSwitched,
diff --git a/core/java/com/android/internal/accessibility/dialog/ToggleAccessibilityServiceTarget.java b/core/java/com/android/internal/accessibility/dialog/ToggleAccessibilityServiceTarget.java
index a4ffef6..a6ef73e 100644
--- a/core/java/com/android/internal/accessibility/dialog/ToggleAccessibilityServiceTarget.java
+++ b/core/java/com/android/internal/accessibility/dialog/ToggleAccessibilityServiceTarget.java
@@ -22,9 +22,9 @@
import android.annotation.NonNull;
import android.content.Context;
import android.view.View;
-import android.view.accessibility.AccessibilityManager.ShortcutType;
import com.android.internal.R;
+import com.android.internal.accessibility.common.ShortcutConstants;
import com.android.internal.accessibility.common.ShortcutConstants.AccessibilityFragmentType;
import com.android.internal.accessibility.common.ShortcutConstants.ShortcutMenuMode;
import com.android.internal.accessibility.dialog.TargetAdapter.ViewHolder;
@@ -45,7 +45,8 @@
float DISABLED = 0.5f;
}
- ToggleAccessibilityServiceTarget(Context context, @ShortcutType int shortcutType,
+ ToggleAccessibilityServiceTarget(Context context,
+ @ShortcutConstants.UserShortcutType int shortcutType,
@NonNull AccessibilityServiceInfo serviceInfo) {
super(context,
shortcutType,
diff --git a/core/java/com/android/internal/accessibility/dialog/ToggleAllowListingFeatureTarget.java b/core/java/com/android/internal/accessibility/dialog/ToggleAllowListingFeatureTarget.java
index 11e668f..2a9c555 100644
--- a/core/java/com/android/internal/accessibility/dialog/ToggleAllowListingFeatureTarget.java
+++ b/core/java/com/android/internal/accessibility/dialog/ToggleAllowListingFeatureTarget.java
@@ -21,9 +21,9 @@
import android.graphics.drawable.Drawable;
import android.provider.Settings;
import android.view.View;
-import android.view.accessibility.AccessibilityManager.ShortcutType;
import com.android.internal.R;
+import com.android.internal.accessibility.common.ShortcutConstants;
import com.android.internal.accessibility.common.ShortcutConstants.AccessibilityFragmentType;
import com.android.internal.accessibility.common.ShortcutConstants.ShortcutMenuMode;
import com.android.internal.accessibility.dialog.TargetAdapter.ViewHolder;
@@ -34,7 +34,8 @@
*/
class ToggleAllowListingFeatureTarget extends AccessibilityTarget {
- ToggleAllowListingFeatureTarget(Context context, @ShortcutType int shortcutType,
+ ToggleAllowListingFeatureTarget(Context context,
+ @ShortcutConstants.UserShortcutType int shortcutType,
boolean isShortcutSwitched, String id, int uid, CharSequence label, Drawable icon,
String key) {
super(context, shortcutType, AccessibilityFragmentType.TOGGLE, isShortcutSwitched, id,
diff --git a/core/java/com/android/internal/accessibility/dialog/VolumeShortcutToggleAccessibilityServiceTarget.java b/core/java/com/android/internal/accessibility/dialog/VolumeShortcutToggleAccessibilityServiceTarget.java
index 04f5061..4926e72 100644
--- a/core/java/com/android/internal/accessibility/dialog/VolumeShortcutToggleAccessibilityServiceTarget.java
+++ b/core/java/com/android/internal/accessibility/dialog/VolumeShortcutToggleAccessibilityServiceTarget.java
@@ -16,9 +16,6 @@
package com.android.internal.accessibility.dialog;
-import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_BUTTON;
-import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_SHORTCUT_KEY;
-
import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType;
import static com.android.internal.accessibility.util.AccessibilityUtils.setAccessibilityServiceState;
import static com.android.internal.accessibility.util.ShortcutUtils.optOutValueFromSettings;
@@ -27,7 +24,6 @@
import android.annotation.NonNull;
import android.content.ComponentName;
import android.content.Context;
-import android.view.accessibility.AccessibilityManager.ShortcutType;
import android.widget.Toast;
import com.android.internal.R;
@@ -39,7 +35,8 @@
*/
class VolumeShortcutToggleAccessibilityServiceTarget extends AccessibilityServiceTarget {
- VolumeShortcutToggleAccessibilityServiceTarget(Context context, @ShortcutType int shortcutType,
+ VolumeShortcutToggleAccessibilityServiceTarget(Context context,
+ @UserShortcutType int shortcutType,
@NonNull AccessibilityServiceInfo serviceInfo) {
super(context,
shortcutType,
@@ -50,10 +47,10 @@
@Override
public void onCheckedChanged(boolean isChecked) {
switch (getShortcutType()) {
- case ACCESSIBILITY_BUTTON:
+ case UserShortcutType.SOFTWARE:
onCheckedFromAccessibilityButton(isChecked);
return;
- case ACCESSIBILITY_SHORTCUT_KEY:
+ case UserShortcutType.HARDWARE:
super.onCheckedChanged(isChecked);
return;
default:
diff --git a/core/java/com/android/internal/accessibility/util/AccessibilityStatsLogUtils.java b/core/java/com/android/internal/accessibility/util/AccessibilityStatsLogUtils.java
index 6b074a6..1e4bcf2 100644
--- a/core/java/com/android/internal/accessibility/util/AccessibilityStatsLogUtils.java
+++ b/core/java/com/android/internal/accessibility/util/AccessibilityStatsLogUtils.java
@@ -21,8 +21,6 @@
import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_ALL;
import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN;
import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW;
-import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_BUTTON;
-import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_SHORTCUT_KEY;
import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_COMPONENT_NAME;
import static com.android.internal.util.FrameworkStatsLog.ACCESSIBILITY_SHORTCUT_REPORTED__SERVICE_STATUS__DISABLED;
@@ -47,9 +45,8 @@
import android.content.ComponentName;
import android.content.Context;
import android.provider.Settings;
-import android.view.accessibility.AccessibilityManager;
-import android.view.accessibility.AccessibilityManager.ShortcutType;
+import com.android.internal.accessibility.common.ShortcutConstants;
import com.android.internal.util.FrameworkStatsLog;
/** Methods for logging accessibility states. */
@@ -71,15 +68,15 @@
/**
* Logs accessibility feature name that is assigned to the given {@code shortcutType}.
- * Calls this when clicking the shortcut {@link AccessibilityManager#ACCESSIBILITY_BUTTON} or
- * {@link AccessibilityManager#ACCESSIBILITY_SHORTCUT_KEY}.
+ * Calls this when clicking the shortcut {@link ShortcutConstants.UserShortcutType.SOFTWARE} or
+ * {@link ShortcutConstants.UserShortcutType.HARDWARE}.
*
* @param context context used to retrieve the {@link Settings} provider
* @param componentName component name of the accessibility feature
* @param shortcutType accessibility shortcut type
*/
public static void logAccessibilityShortcutActivated(Context context,
- ComponentName componentName, @ShortcutType int shortcutType) {
+ ComponentName componentName, @ShortcutConstants.UserShortcutType int shortcutType) {
logAccessibilityShortcutActivatedInternal(componentName,
convertToLoggingShortcutType(context, shortcutType), UNKNOWN_STATUS);
}
@@ -87,8 +84,8 @@
/**
* Logs accessibility feature name that is assigned to the given {@code shortcutType} and the
* {@code serviceEnabled} status.
- * Calls this when clicking the shortcut {@link AccessibilityManager#ACCESSIBILITY_BUTTON}
- * or {@link AccessibilityManager#ACCESSIBILITY_SHORTCUT_KEY}.
+ * Calls this when clicking the shortcut {@link ShortcutConstants.UserShortcutType.SOFTWARE}
+ * or {@link ShortcutConstants.UserShortcutType.HARDWARE}.
*
* @param context context used to retrieve the {@link Settings} provider
* @param componentName component name of the accessibility feature
@@ -96,7 +93,8 @@
* @param serviceEnabled {@code true} if the service is enabled
*/
public static void logAccessibilityShortcutActivated(Context context,
- ComponentName componentName, @ShortcutType int shortcutType, boolean serviceEnabled) {
+ ComponentName componentName, @ShortcutConstants.UserShortcutType int shortcutType,
+ boolean serviceEnabled) {
logAccessibilityShortcutActivatedInternal(componentName,
convertToLoggingShortcutType(context, shortcutType),
convertToLoggingServiceStatus(serviceEnabled));
@@ -235,9 +233,9 @@
}
private static int convertToLoggingShortcutType(Context context,
- @ShortcutType int shortcutType) {
+ @ShortcutConstants.UserShortcutType int shortcutType) {
switch (shortcutType) {
- case ACCESSIBILITY_BUTTON:
+ case ShortcutConstants.UserShortcutType.SOFTWARE:
if (isAccessibilityFloatingMenuEnabled(context)) {
return ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__A11Y_FLOATING_MENU;
} else if (isAccessibilityGestureEnabled(context)) {
@@ -245,7 +243,7 @@
} else {
return ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__A11Y_BUTTON;
}
- case ACCESSIBILITY_SHORTCUT_KEY:
+ case ShortcutConstants.UserShortcutType.HARDWARE:
return ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__VOLUME_KEY;
}
return ACCESSIBILITY_SHORTCUT_REPORTED__SHORTCUT_TYPE__UNKNOWN_TYPE;
diff --git a/core/java/com/android/internal/accessibility/util/ShortcutUtils.java b/core/java/com/android/internal/accessibility/util/ShortcutUtils.java
index 3fd3030..276c5c4 100644
--- a/core/java/com/android/internal/accessibility/util/ShortcutUtils.java
+++ b/core/java/com/android/internal/accessibility/util/ShortcutUtils.java
@@ -16,9 +16,6 @@
package com.android.internal.accessibility.util;
-import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_BUTTON;
-import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_SHORTCUT_KEY;
-
import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_CONTROLLER_NAME;
import static com.android.internal.accessibility.common.ShortcutConstants.AccessibilityFragmentType.INVISIBLE_TOGGLE;
import static com.android.internal.accessibility.common.ShortcutConstants.SERVICES_SEPARATOR;
@@ -33,7 +30,6 @@
import android.text.TextUtils;
import android.util.ArraySet;
import android.view.accessibility.AccessibilityManager;
-import android.view.accessibility.AccessibilityManager.ShortcutType;
import java.util.Collections;
import java.util.List;
@@ -144,7 +140,7 @@
* @param componentId The component id that need to be checked.
* @return {@code true} if a component id is contained.
*/
- public static boolean isShortcutContained(Context context, @ShortcutType int shortcutType,
+ public static boolean isShortcutContained(Context context, @UserShortcutType int shortcutType,
@NonNull String componentId) {
final AccessibilityManager am = (AccessibilityManager) context.getSystemService(
Context.ACCESSIBILITY_SERVICE);
@@ -166,6 +162,8 @@
return Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE;
case UserShortcutType.TRIPLETAP:
return Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED;
+ case UserShortcutType.TWO_FINGERS_TRIPLE_TAP:
+ return Settings.Secure.ACCESSIBILITY_MAGNIFICATION_TWO_FINGER_TRIPLE_TAP_ENABLED;
default:
throw new IllegalArgumentException(
"Unsupported user shortcut type: " + type);
@@ -173,24 +171,6 @@
}
/**
- * Converts {@link ShortcutType} to {@link UserShortcutType}.
- *
- * @param type The shortcut type.
- * @return Mapping type from {@link UserShortcutType}.
- */
- public static @UserShortcutType int convertToUserType(@ShortcutType int type) {
- switch (type) {
- case ACCESSIBILITY_BUTTON:
- return UserShortcutType.SOFTWARE;
- case ACCESSIBILITY_SHORTCUT_KEY:
- return UserShortcutType.HARDWARE;
- default:
- throw new IllegalArgumentException(
- "Unsupported shortcut type:" + type);
- }
- }
-
- /**
* Updates an accessibility state if the accessibility service is a Always-On a11y service,
* a.k.a. AccessibilityServices that has FLAG_REQUEST_ACCESSIBILITY_BUTTON
* <p>
@@ -255,12 +235,13 @@
public static Set<String> getShortcutTargetsFromSettings(
Context context, @UserShortcutType int shortcutType, int userId) {
final String targetKey = convertToKey(shortcutType);
- if (Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED.equals(targetKey)) {
+ if (Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED.equals(targetKey)
+ || Settings.Secure.ACCESSIBILITY_MAGNIFICATION_TWO_FINGER_TRIPLE_TAP_ENABLED
+ .equals(targetKey)) {
boolean magnificationEnabled = Settings.Secure.getIntForUser(
context.getContentResolver(), targetKey, /* def= */ 0, userId) == 1;
return magnificationEnabled ? Set.of(MAGNIFICATION_CONTROLLER_NAME)
: Collections.emptySet();
-
} else {
final String targetString = Settings.Secure.getStringForUser(
context.getContentResolver(), targetKey, userId);
diff --git a/core/java/com/android/internal/os/BatteryStatsHistory.java b/core/java/com/android/internal/os/BatteryStatsHistory.java
index 7a79e0f..aa60cc9 100644
--- a/core/java/com/android/internal/os/BatteryStatsHistory.java
+++ b/core/java/com/android/internal/os/BatteryStatsHistory.java
@@ -490,7 +490,7 @@
* Returns true if this instance only supports reading history.
*/
public boolean isReadOnly() {
- return mActiveFile == null || mHistoryDir == null;
+ return !mMutable || mActiveFile == null || mHistoryDir == null;
}
/**
@@ -508,6 +508,13 @@
* create next history file.
*/
public void startNextFile(long elapsedRealtimeMs) {
+ synchronized (this) {
+ startNextFileLocked(elapsedRealtimeMs);
+ }
+ }
+
+ @GuardedBy("this")
+ private void startNextFileLocked(long elapsedRealtimeMs) {
if (mMaxHistoryFiles == 0) {
Slog.wtf(TAG, "mMaxHistoryFiles should not be zero when writing history");
return;
@@ -548,10 +555,7 @@
}
mWrittenPowerStatsDescriptors.clear();
-
- synchronized (this) {
- cleanupLocked();
- }
+ cleanupLocked();
}
@GuardedBy("this")
@@ -599,27 +603,31 @@
* number 0 again.
*/
public void reset() {
- if (DEBUG) Slog.i(TAG, "********** CLEARING HISTORY!");
- for (BatteryHistoryFile file : mHistoryFiles) {
- file.atomicFile.delete();
+ synchronized (this) {
+ if (DEBUG) Slog.i(TAG, "********** CLEARING HISTORY!");
+ for (BatteryHistoryFile file : mHistoryFiles) {
+ file.atomicFile.delete();
+ }
+ mHistoryFiles.clear();
+
+ BatteryHistoryFile name = makeBatteryHistoryFile();
+ mHistoryFiles.add(name);
+ setActiveFile(name);
+
+ initHistoryBuffer();
}
- mHistoryFiles.clear();
-
- BatteryHistoryFile name = makeBatteryHistoryFile();
- mHistoryFiles.add(name);
- setActiveFile(name);
-
- initHistoryBuffer();
}
/**
* Returns the monotonic clock time when the available battery history collection started.
*/
public long getStartTime() {
- if (!mHistoryFiles.isEmpty()) {
- return mHistoryFiles.get(0).monotonicTimeMs;
- } else {
- return mHistoryBufferStartTime;
+ synchronized (this) {
+ if (!mHistoryFiles.isEmpty()) {
+ return mHistoryFiles.get(0).monotonicTimeMs;
+ } else {
+ return mHistoryBufferStartTime;
+ }
}
}
@@ -633,11 +641,14 @@
*/
@NonNull
public BatteryStatsHistoryIterator iterate(long startTimeMs, long endTimeMs) {
+ if (mMutable) {
+ return copy().iterate(startTimeMs, endTimeMs);
+ }
+
mCurrentFileIndex = 0;
mCurrentParcel = null;
mCurrentParcelEnd = 0;
mParcelIndex = 0;
- mMutable = false;
if (mWritableHistory != null) {
synchronized (mWritableHistory) {
mWritableHistory.setCleanupEnabledLocked(false);
@@ -650,14 +661,11 @@
* Finish iterating history files and history buffer.
*/
void iteratorFinished() {
- // setDataPosition so mHistoryBuffer Parcel can be written.
mHistoryBuffer.setDataPosition(mHistoryBuffer.dataSize());
if (mWritableHistory != null) {
synchronized (mWritableHistory) {
mWritableHistory.setCleanupEnabledLocked(true);
}
- } else {
- mMutable = true;
}
}
@@ -671,6 +679,8 @@
*/
@Nullable
public Parcel getNextParcel(long startTimeMs, long endTimeMs) {
+ checkImmutable();
+
// First iterate through all records in current parcel.
if (mCurrentParcel != null) {
if (mCurrentParcel.dataPosition() < mCurrentParcelEnd) {
@@ -754,6 +764,12 @@
return mCurrentParcel;
}
+ private void checkImmutable() {
+ if (mMutable) {
+ throw new IllegalStateException("Iterating over a mutable battery history");
+ }
+ }
+
/**
* Read history file into a parcel.
*
@@ -863,8 +879,10 @@
* @param out the output parcel
*/
public void writeToParcel(Parcel out) {
- writeHistoryBuffer(out);
- writeToParcel(out, false /* useBlobs */);
+ synchronized (this) {
+ writeHistoryBuffer(out);
+ writeToParcel(out, false /* useBlobs */);
+ }
}
/**
@@ -874,8 +892,10 @@
* @param out the output parcel
*/
public void writeToBatteryUsageStatsParcel(Parcel out) {
- out.writeBlob(mHistoryBuffer.marshall());
- writeToParcel(out, true /* useBlobs */);
+ synchronized (this) {
+ out.writeBlob(mHistoryBuffer.marshall());
+ writeToParcel(out, true /* useBlobs */);
+ }
}
private void writeToParcel(Parcel out, boolean useBlobs) {
@@ -1022,14 +1042,18 @@
* Enables/disables recording of history. When disabled, all "record*" calls are a no-op.
*/
public void setHistoryRecordingEnabled(boolean enabled) {
- mRecordingHistory = enabled;
+ synchronized (this) {
+ mRecordingHistory = enabled;
+ }
}
/**
* Returns true if history recording is enabled.
*/
public boolean isRecordingHistory() {
- return mRecordingHistory;
+ synchronized (this) {
+ return mRecordingHistory;
+ }
}
/**
@@ -1037,8 +1061,10 @@
*/
@VisibleForTesting
public void forceRecordAllHistory() {
- mHaveBatteryLevel = true;
- mRecordingHistory = true;
+ synchronized (this) {
+ mHaveBatteryLevel = true;
+ mRecordingHistory = true;
+ }
}
/**
@@ -1046,37 +1072,43 @@
*/
public void startRecordingHistory(final long elapsedRealtimeMs, final long uptimeMs,
boolean reset) {
- mRecordingHistory = true;
- mHistoryCur.currentTime = mClock.currentTimeMillis();
- writeHistoryItem(elapsedRealtimeMs, uptimeMs, mHistoryCur,
- reset ? HistoryItem.CMD_RESET : HistoryItem.CMD_CURRENT_TIME);
- mHistoryCur.currentTime = 0;
+ synchronized (this) {
+ mRecordingHistory = true;
+ mHistoryCur.currentTime = mClock.currentTimeMillis();
+ writeHistoryItem(elapsedRealtimeMs, uptimeMs, mHistoryCur,
+ reset ? HistoryItem.CMD_RESET : HistoryItem.CMD_CURRENT_TIME);
+ mHistoryCur.currentTime = 0;
+ }
}
/**
* Prepares to continue recording after restoring previous history from persistent storage.
*/
public void continueRecordingHistory() {
- if (mHistoryBuffer.dataPosition() <= 0 && mHistoryFiles.size() <= 1) {
- return;
- }
+ synchronized (this) {
+ if (mHistoryBuffer.dataPosition() <= 0 && mHistoryFiles.size() <= 1) {
+ return;
+ }
- mRecordingHistory = true;
- final long elapsedRealtimeMs = mClock.elapsedRealtime();
- final long uptimeMs = mClock.uptimeMillis();
- writeHistoryItem(elapsedRealtimeMs, uptimeMs, mHistoryCur, HistoryItem.CMD_START);
- startRecordingHistory(elapsedRealtimeMs, uptimeMs, false);
+ mRecordingHistory = true;
+ final long elapsedRealtimeMs = mClock.elapsedRealtime();
+ final long uptimeMs = mClock.uptimeMillis();
+ writeHistoryItem(elapsedRealtimeMs, uptimeMs, mHistoryCur, HistoryItem.CMD_START);
+ startRecordingHistory(elapsedRealtimeMs, uptimeMs, false);
+ }
}
/**
* Notes the current battery state to be reflected in the next written history item.
*/
public void setBatteryState(boolean charging, int status, int level, int chargeUah) {
- mHaveBatteryLevel = true;
- setChargingState(charging);
- mHistoryCur.batteryStatus = (byte) status;
- mHistoryCur.batteryLevel = (byte) level;
- mHistoryCur.batteryChargeUah = chargeUah;
+ synchronized (this) {
+ mHaveBatteryLevel = true;
+ setChargingState(charging);
+ mHistoryCur.batteryStatus = (byte) status;
+ mHistoryCur.batteryLevel = (byte) level;
+ mHistoryCur.batteryChargeUah = chargeUah;
+ }
}
/**
@@ -1084,24 +1116,28 @@
*/
public void setBatteryState(int status, int level, int health, int plugType, int temperature,
int voltageMv, int chargeUah) {
- mHaveBatteryLevel = true;
- mHistoryCur.batteryStatus = (byte) status;
- mHistoryCur.batteryLevel = (byte) level;
- mHistoryCur.batteryHealth = (byte) health;
- mHistoryCur.batteryPlugType = (byte) plugType;
- mHistoryCur.batteryTemperature = (short) temperature;
- mHistoryCur.batteryVoltage = (char) voltageMv;
- mHistoryCur.batteryChargeUah = chargeUah;
+ synchronized (this) {
+ mHaveBatteryLevel = true;
+ mHistoryCur.batteryStatus = (byte) status;
+ mHistoryCur.batteryLevel = (byte) level;
+ mHistoryCur.batteryHealth = (byte) health;
+ mHistoryCur.batteryPlugType = (byte) plugType;
+ mHistoryCur.batteryTemperature = (short) temperature;
+ mHistoryCur.batteryVoltage = (char) voltageMv;
+ mHistoryCur.batteryChargeUah = chargeUah;
+ }
}
/**
* Notes the current power plugged-in state to be reflected in the next written history item.
*/
public void setPluggedInState(boolean pluggedIn) {
- if (pluggedIn) {
- mHistoryCur.states |= HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
- } else {
- mHistoryCur.states &= ~HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
+ synchronized (this) {
+ if (pluggedIn) {
+ mHistoryCur.states |= HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
+ } else {
+ mHistoryCur.states &= ~HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
+ }
}
}
@@ -1109,10 +1145,12 @@
* Notes the current battery charging state to be reflected in the next written history item.
*/
public void setChargingState(boolean charging) {
- if (charging) {
- mHistoryCur.states2 |= HistoryItem.STATE2_CHARGING_FLAG;
- } else {
- mHistoryCur.states2 &= ~HistoryItem.STATE2_CHARGING_FLAG;
+ synchronized (this) {
+ if (charging) {
+ mHistoryCur.states2 |= HistoryItem.STATE2_CHARGING_FLAG;
+ } else {
+ mHistoryCur.states2 &= ~HistoryItem.STATE2_CHARGING_FLAG;
+ }
}
}
@@ -1121,38 +1159,44 @@
*/
public void recordEvent(long elapsedRealtimeMs, long uptimeMs, int code, String name,
int uid) {
- mHistoryCur.eventCode = code;
- mHistoryCur.eventTag = mHistoryCur.localEventTag;
- mHistoryCur.eventTag.string = name;
- mHistoryCur.eventTag.uid = uid;
- writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+ synchronized (this) {
+ mHistoryCur.eventCode = code;
+ mHistoryCur.eventTag = mHistoryCur.localEventTag;
+ mHistoryCur.eventTag.string = name;
+ mHistoryCur.eventTag.uid = uid;
+ writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+ }
}
/**
* Records a time change event.
*/
public void recordCurrentTimeChange(long elapsedRealtimeMs, long uptimeMs, long currentTimeMs) {
- if (!mRecordingHistory) {
- return;
- }
+ synchronized (this) {
+ if (!mRecordingHistory) {
+ return;
+ }
- mHistoryCur.currentTime = currentTimeMs;
- writeHistoryItem(elapsedRealtimeMs, uptimeMs, mHistoryCur,
- HistoryItem.CMD_CURRENT_TIME);
- mHistoryCur.currentTime = 0;
+ mHistoryCur.currentTime = currentTimeMs;
+ writeHistoryItem(elapsedRealtimeMs, uptimeMs, mHistoryCur,
+ HistoryItem.CMD_CURRENT_TIME);
+ mHistoryCur.currentTime = 0;
+ }
}
/**
* Records a system shutdown event.
*/
public void recordShutdownEvent(long elapsedRealtimeMs, long uptimeMs, long currentTimeMs) {
- if (!mRecordingHistory) {
- return;
- }
+ synchronized (this) {
+ if (!mRecordingHistory) {
+ return;
+ }
- mHistoryCur.currentTime = currentTimeMs;
- writeHistoryItem(elapsedRealtimeMs, uptimeMs, mHistoryCur, HistoryItem.CMD_SHUTDOWN);
- mHistoryCur.currentTime = 0;
+ mHistoryCur.currentTime = currentTimeMs;
+ writeHistoryItem(elapsedRealtimeMs, uptimeMs, mHistoryCur, HistoryItem.CMD_SHUTDOWN);
+ mHistoryCur.currentTime = 0;
+ }
}
/**
@@ -1160,13 +1204,15 @@
*/
public void recordBatteryState(long elapsedRealtimeMs, long uptimeMs, int batteryLevel,
boolean isPlugged) {
- mHistoryCur.batteryLevel = (byte) batteryLevel;
- setPluggedInState(isPlugged);
- if (DEBUG) {
- Slog.v(TAG, "Battery unplugged to: "
- + Integer.toHexString(mHistoryCur.states));
+ synchronized (this) {
+ mHistoryCur.batteryLevel = (byte) batteryLevel;
+ setPluggedInState(isPlugged);
+ if (DEBUG) {
+ Slog.v(TAG, "Battery unplugged to: "
+ + Integer.toHexString(mHistoryCur.states));
+ }
+ writeHistoryItem(elapsedRealtimeMs, uptimeMs);
}
- writeHistoryItem(elapsedRealtimeMs, uptimeMs);
}
/**
@@ -1174,9 +1220,11 @@
*/
public void recordPowerStats(long elapsedRealtimeMs, long uptimeMs,
PowerStats powerStats) {
- mHistoryCur.powerStats = powerStats;
- mHistoryCur.states2 |= HistoryItem.STATE2_EXTENSIONS_FLAG;
- writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+ synchronized (this) {
+ mHistoryCur.powerStats = powerStats;
+ mHistoryCur.states2 |= HistoryItem.STATE2_EXTENSIONS_FLAG;
+ writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+ }
}
/**
@@ -1184,11 +1232,13 @@
*/
public void recordProcessStateChange(long elapsedRealtimeMs, long uptimeMs,
int uid, @BatteryConsumer.ProcessState int processState) {
- mHistoryCur.processStateChange = mHistoryCur.localProcessStateChange;
- mHistoryCur.processStateChange.uid = uid;
- mHistoryCur.processStateChange.processState = processState;
- mHistoryCur.states2 |= HistoryItem.STATE2_EXTENSIONS_FLAG;
- writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+ synchronized (this) {
+ mHistoryCur.processStateChange = mHistoryCur.localProcessStateChange;
+ mHistoryCur.processStateChange.uid = uid;
+ mHistoryCur.processStateChange.processState = processState;
+ mHistoryCur.states2 |= HistoryItem.STATE2_EXTENSIONS_FLAG;
+ writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+ }
}
/**
@@ -1197,8 +1247,10 @@
*/
public void recordWifiConsumedCharge(long elapsedRealtimeMs, long uptimeMs,
double monitoredRailChargeMah) {
- mHistoryCur.wifiRailChargeMah += monitoredRailChargeMah;
- writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+ synchronized (this) {
+ mHistoryCur.wifiRailChargeMah += monitoredRailChargeMah;
+ writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+ }
}
/**
@@ -1206,10 +1258,12 @@
*/
public void recordWakelockStartEvent(long elapsedRealtimeMs, long uptimeMs, String historyName,
int uid) {
- mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag;
- mHistoryCur.wakelockTag.string = historyName;
- mHistoryCur.wakelockTag.uid = uid;
- recordStateStartEvent(elapsedRealtimeMs, uptimeMs, HistoryItem.STATE_WAKE_LOCK_FLAG);
+ synchronized (this) {
+ mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag;
+ mHistoryCur.wakelockTag.string = historyName;
+ mHistoryCur.wakelockTag.uid = uid;
+ recordStateStartEvent(elapsedRealtimeMs, uptimeMs, HistoryItem.STATE_WAKE_LOCK_FLAG);
+ }
}
/**
@@ -1217,18 +1271,20 @@
*/
public boolean maybeUpdateWakelockTag(long elapsedRealtimeMs, long uptimeMs, String historyName,
int uid) {
- if (mHistoryLastWritten.cmd != HistoryItem.CMD_UPDATE) {
- return false;
+ synchronized (this) {
+ if (mHistoryLastWritten.cmd != HistoryItem.CMD_UPDATE) {
+ return false;
+ }
+ if (mHistoryLastWritten.wakelockTag != null) {
+ // We'll try to update the last tag.
+ mHistoryLastWritten.wakelockTag = null;
+ mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag;
+ mHistoryCur.wakelockTag.string = historyName;
+ mHistoryCur.wakelockTag.uid = uid;
+ writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+ }
+ return true;
}
- if (mHistoryLastWritten.wakelockTag != null) {
- // We'll try to update the last tag.
- mHistoryLastWritten.wakelockTag = null;
- mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag;
- mHistoryCur.wakelockTag.string = historyName;
- mHistoryCur.wakelockTag.uid = uid;
- writeHistoryItem(elapsedRealtimeMs, uptimeMs);
- }
- return true;
}
/**
@@ -1236,26 +1292,32 @@
*/
public void recordWakelockStopEvent(long elapsedRealtimeMs, long uptimeMs, String historyName,
int uid) {
- mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag;
- mHistoryCur.wakelockTag.string = historyName != null ? historyName : "";
- mHistoryCur.wakelockTag.uid = uid;
- recordStateStopEvent(elapsedRealtimeMs, uptimeMs, HistoryItem.STATE_WAKE_LOCK_FLAG);
+ synchronized (this) {
+ mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag;
+ mHistoryCur.wakelockTag.string = historyName != null ? historyName : "";
+ mHistoryCur.wakelockTag.uid = uid;
+ recordStateStopEvent(elapsedRealtimeMs, uptimeMs, HistoryItem.STATE_WAKE_LOCK_FLAG);
+ }
}
/**
* Records an event when some state flag changes to true.
*/
public void recordStateStartEvent(long elapsedRealtimeMs, long uptimeMs, int stateFlags) {
- mHistoryCur.states |= stateFlags;
- writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+ synchronized (this) {
+ mHistoryCur.states |= stateFlags;
+ writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+ }
}
/**
* Records an event when some state flag changes to false.
*/
public void recordStateStopEvent(long elapsedRealtimeMs, long uptimeMs, int stateFlags) {
- mHistoryCur.states &= ~stateFlags;
- writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+ synchronized (this) {
+ mHistoryCur.states &= ~stateFlags;
+ writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+ }
}
/**
@@ -1263,34 +1325,42 @@
*/
public void recordStateChangeEvent(long elapsedRealtimeMs, long uptimeMs, int stateStartFlags,
int stateStopFlags) {
- mHistoryCur.states = (mHistoryCur.states | stateStartFlags) & ~stateStopFlags;
- writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+ synchronized (this) {
+ mHistoryCur.states = (mHistoryCur.states | stateStartFlags) & ~stateStopFlags;
+ writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+ }
}
/**
* Records an event when some state2 flag changes to true.
*/
public void recordState2StartEvent(long elapsedRealtimeMs, long uptimeMs, int stateFlags) {
- mHistoryCur.states2 |= stateFlags;
- writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+ synchronized (this) {
+ mHistoryCur.states2 |= stateFlags;
+ writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+ }
}
/**
* Records an event when some state2 flag changes to false.
*/
public void recordState2StopEvent(long elapsedRealtimeMs, long uptimeMs, int stateFlags) {
- mHistoryCur.states2 &= ~stateFlags;
- writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+ synchronized (this) {
+ mHistoryCur.states2 &= ~stateFlags;
+ writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+ }
}
/**
* Records an wakeup event.
*/
public void recordWakeupEvent(long elapsedRealtimeMs, long uptimeMs, String reason) {
- mHistoryCur.wakeReasonTag = mHistoryCur.localWakeReasonTag;
- mHistoryCur.wakeReasonTag.string = reason;
- mHistoryCur.wakeReasonTag.uid = 0;
- writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+ synchronized (this) {
+ mHistoryCur.wakeReasonTag = mHistoryCur.localWakeReasonTag;
+ mHistoryCur.wakeReasonTag.string = reason;
+ mHistoryCur.wakeReasonTag.uid = 0;
+ writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+ }
}
/**
@@ -1298,10 +1368,12 @@
*/
public void recordScreenBrightnessEvent(long elapsedRealtimeMs, long uptimeMs,
int brightnessBin) {
- mHistoryCur.states = setBitField(mHistoryCur.states, brightnessBin,
- HistoryItem.STATE_BRIGHTNESS_SHIFT,
- HistoryItem.STATE_BRIGHTNESS_MASK);
- writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+ synchronized (this) {
+ mHistoryCur.states = setBitField(mHistoryCur.states, brightnessBin,
+ HistoryItem.STATE_BRIGHTNESS_SHIFT,
+ HistoryItem.STATE_BRIGHTNESS_MASK);
+ writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+ }
}
/**
@@ -1309,20 +1381,24 @@
*/
public void recordGpsSignalQualityEvent(long elapsedRealtimeMs, long uptimeMs,
int signalLevel) {
- mHistoryCur.states2 = setBitField(mHistoryCur.states2, signalLevel,
- HistoryItem.STATE2_GPS_SIGNAL_QUALITY_SHIFT,
- HistoryItem.STATE2_GPS_SIGNAL_QUALITY_MASK);
- writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+ synchronized (this) {
+ mHistoryCur.states2 = setBitField(mHistoryCur.states2, signalLevel,
+ HistoryItem.STATE2_GPS_SIGNAL_QUALITY_SHIFT,
+ HistoryItem.STATE2_GPS_SIGNAL_QUALITY_MASK);
+ writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+ }
}
/**
* Records a device idle mode change event.
*/
public void recordDeviceIdleEvent(long elapsedRealtimeMs, long uptimeMs, int mode) {
- mHistoryCur.states2 = setBitField(mHistoryCur.states2, mode,
- HistoryItem.STATE2_DEVICE_IDLE_SHIFT,
- HistoryItem.STATE2_DEVICE_IDLE_MASK);
- writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+ synchronized (this) {
+ mHistoryCur.states2 = setBitField(mHistoryCur.states2, mode,
+ HistoryItem.STATE2_DEVICE_IDLE_SHIFT,
+ HistoryItem.STATE2_DEVICE_IDLE_MASK);
+ writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+ }
}
/**
@@ -1330,20 +1406,22 @@
*/
public void recordPhoneStateChangeEvent(long elapsedRealtimeMs, long uptimeMs, int addStateFlag,
int removeStateFlag, int state, int signalStrength) {
- mHistoryCur.states = (mHistoryCur.states | addStateFlag) & ~removeStateFlag;
- if (state != -1) {
- mHistoryCur.states =
- setBitField(mHistoryCur.states, state,
- HistoryItem.STATE_PHONE_STATE_SHIFT,
- HistoryItem.STATE_PHONE_STATE_MASK);
+ synchronized (this) {
+ mHistoryCur.states = (mHistoryCur.states | addStateFlag) & ~removeStateFlag;
+ if (state != -1) {
+ mHistoryCur.states =
+ setBitField(mHistoryCur.states, state,
+ HistoryItem.STATE_PHONE_STATE_SHIFT,
+ HistoryItem.STATE_PHONE_STATE_MASK);
+ }
+ if (signalStrength != -1) {
+ mHistoryCur.states =
+ setBitField(mHistoryCur.states, signalStrength,
+ HistoryItem.STATE_PHONE_SIGNAL_STRENGTH_SHIFT,
+ HistoryItem.STATE_PHONE_SIGNAL_STRENGTH_MASK);
+ }
+ writeHistoryItem(elapsedRealtimeMs, uptimeMs);
}
- if (signalStrength != -1) {
- mHistoryCur.states =
- setBitField(mHistoryCur.states, signalStrength,
- HistoryItem.STATE_PHONE_SIGNAL_STRENGTH_SHIFT,
- HistoryItem.STATE_PHONE_SIGNAL_STRENGTH_MASK);
- }
- writeHistoryItem(elapsedRealtimeMs, uptimeMs);
}
/**
@@ -1351,10 +1429,12 @@
*/
public void recordDataConnectionTypeChangeEvent(long elapsedRealtimeMs, long uptimeMs,
int dataConnectionType) {
- mHistoryCur.states = setBitField(mHistoryCur.states, dataConnectionType,
- HistoryItem.STATE_DATA_CONNECTION_SHIFT,
- HistoryItem.STATE_DATA_CONNECTION_MASK);
- writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+ synchronized (this) {
+ mHistoryCur.states = setBitField(mHistoryCur.states, dataConnectionType,
+ HistoryItem.STATE_DATA_CONNECTION_SHIFT,
+ HistoryItem.STATE_DATA_CONNECTION_MASK);
+ writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+ }
}
/**
@@ -1362,10 +1442,12 @@
*/
public void recordNrStateChangeEvent(long elapsedRealtimeMs, long uptimeMs,
int nrState) {
- mHistoryCur.states2 = setBitField(mHistoryCur.states2, nrState,
- HistoryItem.STATE2_NR_STATE_SHIFT,
- HistoryItem.STATE2_NR_STATE_MASK);
- writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+ synchronized (this) {
+ mHistoryCur.states2 = setBitField(mHistoryCur.states2, nrState,
+ HistoryItem.STATE2_NR_STATE_SHIFT,
+ HistoryItem.STATE2_NR_STATE_MASK);
+ writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+ }
}
/**
@@ -1373,11 +1455,13 @@
*/
public void recordWifiSupplicantStateChangeEvent(long elapsedRealtimeMs, long uptimeMs,
int supplState) {
- mHistoryCur.states2 =
- setBitField(mHistoryCur.states2, supplState,
- HistoryItem.STATE2_WIFI_SUPPL_STATE_SHIFT,
- HistoryItem.STATE2_WIFI_SUPPL_STATE_MASK);
- writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+ synchronized (this) {
+ mHistoryCur.states2 =
+ setBitField(mHistoryCur.states2, supplState,
+ HistoryItem.STATE2_WIFI_SUPPL_STATE_SHIFT,
+ HistoryItem.STATE2_WIFI_SUPPL_STATE_MASK);
+ writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+ }
}
/**
@@ -1385,11 +1469,13 @@
*/
public void recordWifiSignalStrengthChangeEvent(long elapsedRealtimeMs, long uptimeMs,
int strengthBin) {
- mHistoryCur.states2 =
- setBitField(mHistoryCur.states2, strengthBin,
- HistoryItem.STATE2_WIFI_SIGNAL_STRENGTH_SHIFT,
- HistoryItem.STATE2_WIFI_SIGNAL_STRENGTH_MASK);
- writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+ synchronized (this) {
+ mHistoryCur.states2 =
+ setBitField(mHistoryCur.states2, strengthBin,
+ HistoryItem.STATE2_WIFI_SIGNAL_STRENGTH_SHIFT,
+ HistoryItem.STATE2_WIFI_SIGNAL_STRENGTH_MASK);
+ writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+ }
}
/**
@@ -1446,25 +1532,30 @@
* Writes the current history item to history.
*/
public void writeHistoryItem(long elapsedRealtimeMs, long uptimeMs) {
- if (mTrackRunningHistoryElapsedRealtimeMs != 0) {
- final long diffElapsedMs = elapsedRealtimeMs - mTrackRunningHistoryElapsedRealtimeMs;
- final long diffUptimeMs = uptimeMs - mTrackRunningHistoryUptimeMs;
- if (diffUptimeMs < (diffElapsedMs - 20)) {
- final long wakeElapsedTimeMs = elapsedRealtimeMs - (diffElapsedMs - diffUptimeMs);
- mHistoryAddTmp.setTo(mHistoryLastWritten);
- mHistoryAddTmp.wakelockTag = null;
- mHistoryAddTmp.wakeReasonTag = null;
- mHistoryAddTmp.eventCode = HistoryItem.EVENT_NONE;
- mHistoryAddTmp.states &= ~HistoryItem.STATE_CPU_RUNNING_FLAG;
- writeHistoryItem(wakeElapsedTimeMs, uptimeMs, mHistoryAddTmp);
+ synchronized (this) {
+ if (mTrackRunningHistoryElapsedRealtimeMs != 0) {
+ final long diffElapsedMs =
+ elapsedRealtimeMs - mTrackRunningHistoryElapsedRealtimeMs;
+ final long diffUptimeMs = uptimeMs - mTrackRunningHistoryUptimeMs;
+ if (diffUptimeMs < (diffElapsedMs - 20)) {
+ final long wakeElapsedTimeMs =
+ elapsedRealtimeMs - (diffElapsedMs - diffUptimeMs);
+ mHistoryAddTmp.setTo(mHistoryLastWritten);
+ mHistoryAddTmp.wakelockTag = null;
+ mHistoryAddTmp.wakeReasonTag = null;
+ mHistoryAddTmp.eventCode = HistoryItem.EVENT_NONE;
+ mHistoryAddTmp.states &= ~HistoryItem.STATE_CPU_RUNNING_FLAG;
+ writeHistoryItem(wakeElapsedTimeMs, uptimeMs, mHistoryAddTmp);
+ }
}
+ mHistoryCur.states |= HistoryItem.STATE_CPU_RUNNING_FLAG;
+ mTrackRunningHistoryElapsedRealtimeMs = elapsedRealtimeMs;
+ mTrackRunningHistoryUptimeMs = uptimeMs;
+ writeHistoryItem(elapsedRealtimeMs, uptimeMs, mHistoryCur);
}
- mHistoryCur.states |= HistoryItem.STATE_CPU_RUNNING_FLAG;
- mTrackRunningHistoryElapsedRealtimeMs = elapsedRealtimeMs;
- mTrackRunningHistoryUptimeMs = uptimeMs;
- writeHistoryItem(elapsedRealtimeMs, uptimeMs, mHistoryCur);
}
+ @GuardedBy("this")
private void writeHistoryItem(long elapsedRealtimeMs, long uptimeMs, HistoryItem cur) {
if (mTracer != null && mTracer.tracingEnabled()) {
recordTraceEvents(cur.eventCode, cur.eventTag);
@@ -1591,6 +1682,7 @@
writeHistoryItem(elapsedRealtimeMs, uptimeMs, cur, HistoryItem.CMD_UPDATE);
}
+ @GuardedBy("this")
private void writeHistoryItem(long elapsedRealtimeMs,
@SuppressWarnings("UnusedVariable") long uptimeMs, HistoryItem cur, byte cmd) {
if (!mMutable) {
@@ -1701,7 +1793,8 @@
/**
* Writes the delta between the previous and current history items into history buffer.
*/
- public void writeHistoryDelta(Parcel dest, HistoryItem cur, HistoryItem last) {
+ @GuardedBy("this")
+ private void writeHistoryDelta(Parcel dest, HistoryItem cur, HistoryItem last) {
if (last == null || cur.cmd != HistoryItem.CMD_UPDATE) {
dest.writeInt(BatteryStatsHistory.DELTA_TIME_ABS);
cur.writeToParcel(dest, 0);
@@ -1921,6 +2014,7 @@
* while writing the current history buffer, the method returns
* <code>(index | TAG_FIRST_OCCURRENCE_FLAG)</code>
*/
+ @GuardedBy("this")
private int writeHistoryTag(HistoryTag tag) {
if (tag.string == null) {
Slog.wtfStack(TAG, "writeHistoryTag called with null name");
@@ -1964,33 +2058,37 @@
* Don't allow any more batching in to the current history event.
*/
public void commitCurrentHistoryBatchLocked() {
- mHistoryLastWritten.cmd = HistoryItem.CMD_NULL;
+ synchronized (this) {
+ mHistoryLastWritten.cmd = HistoryItem.CMD_NULL;
+ }
}
/**
* Saves the accumulated history buffer in the active file, see {@link #getActiveFile()} .
*/
public void writeHistory() {
- if (isReadOnly()) {
- Slog.w(TAG, "writeHistory: this instance instance is read-only");
- return;
- }
-
- // Save the monotonic time first, so that even if the history write below fails,
- // we still wouldn't end up with overlapping history timelines.
- mMonotonicClock.write();
-
- Parcel p = Parcel.obtain();
- try {
- final long start = SystemClock.uptimeMillis();
- writeHistoryBuffer(p);
- if (DEBUG) {
- Slog.d(TAG, "writeHistoryBuffer duration ms:"
- + (SystemClock.uptimeMillis() - start) + " bytes:" + p.dataSize());
+ synchronized (this) {
+ if (isReadOnly()) {
+ Slog.w(TAG, "writeHistory: this instance instance is read-only");
+ return;
}
- writeParcelToFileLocked(p, mActiveFile);
- } finally {
- p.recycle();
+
+ // Save the monotonic time first, so that even if the history write below fails,
+ // we still wouldn't end up with overlapping history timelines.
+ mMonotonicClock.write();
+
+ Parcel p = Parcel.obtain();
+ try {
+ final long start = SystemClock.uptimeMillis();
+ writeHistoryBuffer(p);
+ if (DEBUG) {
+ Slog.d(TAG, "writeHistoryBuffer duration ms:"
+ + (SystemClock.uptimeMillis() - start) + " bytes:" + p.dataSize());
+ }
+ writeParcelToFileLocked(p, mActiveFile);
+ } finally {
+ p.recycle();
+ }
}
}
@@ -1998,35 +2096,38 @@
* Reads history buffer from a persisted Parcel.
*/
public void readHistoryBuffer(Parcel in) throws ParcelFormatException {
- final int version = in.readInt();
- if (version != BatteryStatsHistory.VERSION) {
- Slog.w("BatteryStats", "readHistoryBuffer: version got " + version
- + ", expected " + BatteryStatsHistory.VERSION + "; erasing old stats");
- return;
- }
-
- mHistoryBufferStartTime = in.readLong();
- mHistoryBuffer.setDataSize(0);
- mHistoryBuffer.setDataPosition(0);
-
- int bufSize = in.readInt();
- int curPos = in.dataPosition();
- if (bufSize >= (mMaxHistoryBufferSize * 100)) {
- throw new ParcelFormatException(
- "File corrupt: history data buffer too large " + bufSize);
- } else if ((bufSize & ~3) != bufSize) {
- throw new ParcelFormatException(
- "File corrupt: history data buffer not aligned " + bufSize);
- } else {
- if (DEBUG) {
- Slog.i(TAG, "***************** READING NEW HISTORY: " + bufSize
- + " bytes at " + curPos);
+ synchronized (this) {
+ final int version = in.readInt();
+ if (version != BatteryStatsHistory.VERSION) {
+ Slog.w("BatteryStats", "readHistoryBuffer: version got " + version
+ + ", expected " + BatteryStatsHistory.VERSION + "; erasing old stats");
+ return;
}
- mHistoryBuffer.appendFrom(in, curPos, bufSize);
- in.setDataPosition(curPos + bufSize);
+
+ mHistoryBufferStartTime = in.readLong();
+ mHistoryBuffer.setDataSize(0);
+ mHistoryBuffer.setDataPosition(0);
+
+ int bufSize = in.readInt();
+ int curPos = in.dataPosition();
+ if (bufSize >= (mMaxHistoryBufferSize * 100)) {
+ throw new ParcelFormatException(
+ "File corrupt: history data buffer too large " + bufSize);
+ } else if ((bufSize & ~3) != bufSize) {
+ throw new ParcelFormatException(
+ "File corrupt: history data buffer not aligned " + bufSize);
+ } else {
+ if (DEBUG) {
+ Slog.i(TAG, "***************** READING NEW HISTORY: " + bufSize
+ + " bytes at " + curPos);
+ }
+ mHistoryBuffer.appendFrom(in, curPos, bufSize);
+ in.setDataPosition(curPos + bufSize);
+ }
}
}
+ @GuardedBy("this")
private void writeHistoryBuffer(Parcel out) {
out.writeInt(BatteryStatsHistory.VERSION);
out.writeLong(mHistoryBufferStartTime);
@@ -2038,6 +2139,7 @@
out.appendFrom(mHistoryBuffer, 0, mHistoryBuffer.dataSize());
}
+ @GuardedBy("this")
private void writeParcelToFileLocked(Parcel p, AtomicFile file) {
FileOutputStream fos = null;
mWriteLock.lock();
@@ -2066,34 +2168,43 @@
* Returns the total number of history tags in the tag pool.
*/
public int getHistoryStringPoolSize() {
- return mHistoryTagPool.size();
+ synchronized (this) {
+ return mHistoryTagPool.size();
+ }
}
/**
* Returns the total number of bytes occupied by the history tag pool.
*/
public int getHistoryStringPoolBytes() {
- return mNumHistoryTagChars;
+ synchronized (this) {
+ return mNumHistoryTagChars;
+ }
}
/**
* Returns the string held by the requested history tag.
*/
public String getHistoryTagPoolString(int index) {
- ensureHistoryTagArray();
- HistoryTag historyTag = mHistoryTags.get(index);
- return historyTag != null ? historyTag.string : null;
+ synchronized (this) {
+ ensureHistoryTagArray();
+ HistoryTag historyTag = mHistoryTags.get(index);
+ return historyTag != null ? historyTag.string : null;
+ }
}
/**
* Returns the UID held by the requested history tag.
*/
public int getHistoryTagPoolUid(int index) {
- ensureHistoryTagArray();
- HistoryTag historyTag = mHistoryTags.get(index);
- return historyTag != null ? historyTag.uid : Process.INVALID_UID;
+ synchronized (this) {
+ ensureHistoryTagArray();
+ HistoryTag historyTag = mHistoryTags.get(index);
+ return historyTag != null ? historyTag.uid : Process.INVALID_UID;
+ }
}
+ @GuardedBy("this")
private void ensureHistoryTagArray() {
if (mHistoryTags != null) {
return;
diff --git a/core/java/com/android/internal/pm/pkg/component/ParsedIntentInfoUtils.java b/core/java/com/android/internal/pm/pkg/component/ParsedIntentInfoUtils.java
index c6683cf..05728ee 100644
--- a/core/java/com/android/internal/pm/pkg/component/ParsedIntentInfoUtils.java
+++ b/core/java/com/android/internal/pm/pkg/component/ParsedIntentInfoUtils.java
@@ -18,9 +18,13 @@
import static com.android.internal.pm.pkg.parsing.ParsingUtils.ANDROID_RES_NAMESPACE;
+import android.annotation.FlaggedApi;
import android.annotation.NonNull;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.UriRelativeFilter;
+import android.content.UriRelativeFilterGroup;
+import android.content.pm.Flags;
import android.content.pm.parsing.result.ParseInput;
import android.content.pm.parsing.result.ParseResult;
import android.content.res.Resources;
@@ -132,6 +136,11 @@
case "data":
result = parseData(intentInfo, res, parser, allowGlobs, input);
break;
+ case "uri-relative-filter-group":
+ if (Flags.relativeReferenceIntentFilters()) {
+ result = parseRelRefGroup(intentInfo, pkg, res, parser, allowGlobs, input);
+ break;
+ }
default:
result = ParsingUtils.unknownTag("<intent-filter>", pkg, parser, input);
break;
@@ -163,6 +172,197 @@
}
@NonNull
+ @FlaggedApi(Flags.FLAG_RELATIVE_REFERENCE_INTENT_FILTERS)
+ private static ParseResult<ParsedIntentInfo> parseRelRefGroup(ParsedIntentInfo intentInfo,
+ ParsingPackage pkg, Resources res, XmlResourceParser parser, boolean allowGlobs,
+ ParseInput input) throws XmlPullParserException, IOException {
+ IntentFilter intentFilter = intentInfo.getIntentFilter();
+ TypedArray sa = res.obtainAttributes(parser,
+ R.styleable.AndroidManifestUriRelativeFilterGroup);
+ UriRelativeFilterGroup group;
+ try {
+ int action = UriRelativeFilterGroup.ACTION_ALLOW;
+ if (!sa.getBoolean(R.styleable.AndroidManifestUriRelativeFilterGroup_allow, true)) {
+ action = UriRelativeFilterGroup.ACTION_BLOCK;
+ }
+ group = new UriRelativeFilterGroup(action);
+ } finally {
+ sa.recycle();
+ }
+ final int depth = parser.getDepth();
+ int type;
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG
+ || parser.getDepth() > depth)) {
+ if (type != XmlPullParser.START_TAG) {
+ continue;
+ }
+
+ final ParseResult result;
+ String nodeName = parser.getName();
+ switch (nodeName) {
+ case "data":
+ result = parseRelRefGroupData(group, res, parser, allowGlobs, input);
+ break;
+ default:
+ result = ParsingUtils.unknownTag("<uri-relative-filter-group>",
+ pkg, parser, input);
+ break;
+ }
+
+ if (result.isError()) {
+ return input.error(result);
+ }
+ }
+
+ if (group.getUriRelativeFilters().size() > 0) {
+ intentFilter.addUriRelativeFilterGroup(group);
+ }
+ return input.success(null);
+ }
+
+ @NonNull
+ @FlaggedApi(Flags.FLAG_RELATIVE_REFERENCE_INTENT_FILTERS)
+ private static ParseResult<ParsedIntentInfo> parseRelRefGroupData(UriRelativeFilterGroup group,
+ Resources res, XmlResourceParser parser, boolean allowGlobs, ParseInput input) {
+ TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestData);
+ try {
+ String str = sa.getNonConfigurationString(
+ R.styleable.AndroidManifestData_path, 0);
+ if (str != null) {
+ group.addUriRelativeFilter(new UriRelativeFilter(UriRelativeFilter.PATH,
+ PatternMatcher.PATTERN_LITERAL, str));
+ }
+
+ str = sa.getNonConfigurationString(
+ R.styleable.AndroidManifestData_pathPrefix, 0);
+ if (str != null) {
+ group.addUriRelativeFilter(new UriRelativeFilter(UriRelativeFilter.PATH,
+ PatternMatcher.PATTERN_PREFIX, str));
+ }
+
+ str = sa.getNonConfigurationString(
+ R.styleable.AndroidManifestData_pathPattern, 0);
+ if (str != null) {
+ if (!allowGlobs) {
+ return input.error(
+ "pathPattern not allowed here; path must be literal");
+ }
+ group.addUriRelativeFilter(new UriRelativeFilter(UriRelativeFilter.PATH,
+ PatternMatcher.PATTERN_SIMPLE_GLOB, str));
+ }
+
+ str = sa.getNonConfigurationString(
+ R.styleable.AndroidManifestData_pathAdvancedPattern, 0);
+ if (str != null) {
+ if (!allowGlobs) {
+ return input.error(
+ "pathAdvancedPattern not allowed here; path must be literal");
+ }
+ group.addUriRelativeFilter(new UriRelativeFilter(UriRelativeFilter.PATH,
+ PatternMatcher.PATTERN_ADVANCED_GLOB, str));
+ }
+
+ str = sa.getNonConfigurationString(
+ R.styleable.AndroidManifestData_pathSuffix, 0);
+ if (str != null) {
+ group.addUriRelativeFilter(new UriRelativeFilter(UriRelativeFilter.PATH,
+ PatternMatcher.PATTERN_SUFFIX, str));
+ }
+
+ str = sa.getNonConfigurationString(
+ R.styleable.AndroidManifestData_fragment, 0);
+ if (str != null) {
+ group.addUriRelativeFilter(new UriRelativeFilter(UriRelativeFilter.FRAGMENT,
+ PatternMatcher.PATTERN_LITERAL, str));
+ }
+
+ str = sa.getNonConfigurationString(
+ R.styleable.AndroidManifestData_fragmentPrefix, 0);
+ if (str != null) {
+ group.addUriRelativeFilter(new UriRelativeFilter(UriRelativeFilter.FRAGMENT,
+ PatternMatcher.PATTERN_PREFIX, str));
+ }
+
+ str = sa.getNonConfigurationString(
+ R.styleable.AndroidManifestData_fragmentPattern, 0);
+ if (str != null) {
+ if (!allowGlobs) {
+ return input.error(
+ "fragmentPattern not allowed here; fragment must be literal");
+ }
+ group.addUriRelativeFilter(new UriRelativeFilter(UriRelativeFilter.FRAGMENT,
+ PatternMatcher.PATTERN_SIMPLE_GLOB, str));
+ }
+
+ str = sa.getNonConfigurationString(
+ R.styleable.AndroidManifestData_fragmentAdvancedPattern, 0);
+ if (str != null) {
+ if (!allowGlobs) {
+ return input.error(
+ "fragmentAdvancedPattern not allowed here; fragment must be literal");
+ }
+ group.addUriRelativeFilter(new UriRelativeFilter(UriRelativeFilter.FRAGMENT,
+ PatternMatcher.PATTERN_ADVANCED_GLOB, str));
+ }
+
+ str = sa.getNonConfigurationString(
+ R.styleable.AndroidManifestData_fragmentSuffix, 0);
+ if (str != null) {
+ group.addUriRelativeFilter(new UriRelativeFilter(UriRelativeFilter.FRAGMENT,
+ PatternMatcher.PATTERN_SUFFIX, str));
+ }
+
+ str = sa.getNonConfigurationString(
+ R.styleable.AndroidManifestData_query, 0);
+ if (str != null) {
+ group.addUriRelativeFilter(new UriRelativeFilter(UriRelativeFilter.QUERY,
+ PatternMatcher.PATTERN_LITERAL, str));
+ }
+
+ str = sa.getNonConfigurationString(
+ R.styleable.AndroidManifestData_queryPrefix, 0);
+ if (str != null) {
+ group.addUriRelativeFilter(new UriRelativeFilter(UriRelativeFilter.QUERY,
+ PatternMatcher.PATTERN_PREFIX, str));
+ }
+
+ str = sa.getNonConfigurationString(
+ R.styleable.AndroidManifestData_queryPattern, 0);
+ if (str != null) {
+ if (!allowGlobs) {
+ return input.error(
+ "queryPattern not allowed here; query must be literal");
+ }
+ group.addUriRelativeFilter(new UriRelativeFilter(UriRelativeFilter.QUERY,
+ PatternMatcher.PATTERN_SIMPLE_GLOB, str));
+ }
+
+ str = sa.getNonConfigurationString(
+ R.styleable.AndroidManifestData_queryAdvancedPattern, 0);
+ if (str != null) {
+ if (!allowGlobs) {
+ return input.error(
+ "queryAdvancedPattern not allowed here; query must be literal");
+ }
+ group.addUriRelativeFilter(new UriRelativeFilter(UriRelativeFilter.QUERY,
+ PatternMatcher.PATTERN_ADVANCED_GLOB, str));
+ }
+
+ str = sa.getNonConfigurationString(
+ R.styleable.AndroidManifestData_querySuffix, 0);
+ if (str != null) {
+ group.addUriRelativeFilter(new UriRelativeFilter(UriRelativeFilter.QUERY,
+ PatternMatcher.PATTERN_SUFFIX, str));
+ }
+
+ return input.success(null);
+ } finally {
+ sa.recycle();
+ }
+ }
+
+ @NonNull
private static ParseResult<ParsedIntentInfo> parseData(ParsedIntentInfo intentInfo,
Resources resources, XmlResourceParser parser, boolean allowGlobs, ParseInput input) {
IntentFilter intentFilter = intentInfo.getIntentFilter();
diff --git a/core/jni/android_window_ScreenCapture.cpp b/core/jni/android_window_ScreenCapture.cpp
index 6e903b3..1031542 100644
--- a/core/jni/android_window_ScreenCapture.cpp
+++ b/core/jni/android_window_ScreenCapture.cpp
@@ -211,7 +211,7 @@
}
static jint nativeCaptureLayers(JNIEnv* env, jclass clazz, jobject layerCaptureArgsObject,
- jlong screenCaptureListenerObject) {
+ jlong screenCaptureListenerObject, jboolean sync) {
LayerCaptureArgs captureArgs;
getCaptureArgs(env, layerCaptureArgsObject, captureArgs);
@@ -227,7 +227,7 @@
sp<gui::IScreenCaptureListener> captureListener =
reinterpret_cast<gui::IScreenCaptureListener*>(screenCaptureListenerObject);
- return ScreenshotClient::captureLayers(captureArgs, captureListener);
+ return ScreenshotClient::captureLayers(captureArgs, captureListener, sync);
}
static jlong nativeCreateScreenCaptureListener(JNIEnv* env, jclass clazz, jobject consumerObj) {
@@ -281,7 +281,7 @@
// clang-format off
{"nativeCaptureDisplay", "(Landroid/window/ScreenCapture$DisplayCaptureArgs;J)I",
(void*)nativeCaptureDisplay },
- {"nativeCaptureLayers", "(Landroid/window/ScreenCapture$LayerCaptureArgs;J)I",
+ {"nativeCaptureLayers", "(Landroid/window/ScreenCapture$LayerCaptureArgs;JZ)I",
(void*)nativeCaptureLayers },
{"nativeCreateScreenCaptureListener", "(Ljava/util/function/ObjIntConsumer;)J",
(void*)nativeCreateScreenCaptureListener },
diff --git a/core/proto/android/content/intent.proto b/core/proto/android/content/intent.proto
index 75e2908..1d1f88b 100644
--- a/core/proto/android/content/intent.proto
+++ b/core/proto/android/content/intent.proto
@@ -66,7 +66,7 @@
optional string identifier = 13 [ (.android.privacy).dest = DEST_EXPLICIT ];
}
-// Next Tag: 12
+// Next Tag: 14
message IntentFilterProto {
option (.android.msg_privacy).dest = DEST_AUTOMATIC;
@@ -89,6 +89,7 @@
optional bool get_auto_verify = 10;
repeated string mime_groups = 11;
optional android.os.PersistableBundleProto extras = 12;
+ repeated UriRelativeFilterGroupProto uri_relative_filter_groups = 13;
}
message AuthorityEntryProto {
@@ -98,3 +99,23 @@
optional bool wild = 2;
optional int32 port = 3;
}
+
+message UriRelativeFilterGroupProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ enum Action {
+ ACTION_ALLOW = 0;
+ ACTION_BLOCK = 1;
+ }
+
+ optional Action action = 1;
+ repeated UriRelativeFilterProto uri_relative_filters = 2;
+}
+
+message UriRelativeFilterProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ required int32 uri_part = 1;
+ required int32 pattern_type = 2;
+ required string filter = 3;
+}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 0e0af4d..0171f58 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -3751,6 +3751,13 @@
<permission android:name="android.permission.MANAGE_DEVICE_POLICY_DEVICE_IDENTIFIERS"
android:protectionLevel="internal|role" />
+ <!-- Allows an application to manage policy related to content protection.
+ <p>Protection level: internal|role
+ @FlaggedApi("android.view.contentprotection.flags.manage_device_policy_enabled")
+ -->
+ <permission android:name="android.permission.MANAGE_DEVICE_POLICY_CONTENT_PROTECTION"
+ android:protectionLevel="internal|role" />
+
<!-- Allows an application to set device policies outside the current user
that are critical for securing data within the current user.
<p>Holding this permission allows the use of other held MANAGE_DEVICE_POLICY_*
@@ -3828,6 +3835,18 @@
<permission android:name="android.permission.ACTIVITY_EMBEDDING"
android:protectionLevel="signature|privileged" />
+ <!-- Allows an application to embed any other apps in untrusted embedding mode without the need
+ for the embedded app to consent.
+ <p>For now, this permission is only granted to the Assistant application selected by
+ the user.
+ {@see https://developer.android.com/guide/topics/large-screens/activity-embedding#trust_model}
+ @SystemApi
+ @FlaggedApi("com.android.window.flags.untrusted_embedding_any_app_permission")
+ @hide
+ -->
+ <permission android:name="android.permission.EMBED_ANY_APP_IN_UNTRUSTED_MODE"
+ android:protectionLevel="internal|role" />
+
<!-- Allows an application to start any activity, regardless of permission
protection or exported state.
@hide -->
@@ -7985,6 +8004,16 @@
<permission android:name="android.permission.READ_SYSTEM_GRAMMATICAL_GENDER"
android:protectionLevel="signature|privileged"/>
+ <!-- @SystemApi
+ @FlaggedApi("android.content.pm.emergency_install_permission")
+ Allows each app store in the system image to designate another app in the system image to
+ update the app store
+ <p>Protection level: signature|privileged
+ @hide
+ -->
+ <permission android:name="android.permission.EMERGENCY_INSTALL_PACKAGES"
+ android:protectionLevel="signature|privileged"/>
+
<!-- Attribution for Geofencing service. -->
<attribution android:tag="GeofencingService" android:label="@string/geofencing_service"/>
<!-- Attribution for Country Detector. -->
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 38d2a25..e864872 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -370,6 +370,10 @@
<string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Laat die program toe om die seluitsendingmodule te bind om seluitsendingboodskappe aan te stuur wanneer hulle ontvang word. Seluitsendingwaarskuwings word in sommige liggings gelewer om jou oor noodsituasies te waarsku. Kwaadwillige programme kan met die werkverrigting of werking van jou toestel inmeng wanneer \'n noodseluitsending ontvang word."</string>
<string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Bestuur voortgaande oproepe"</string>
<string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Stel \'n program in staat om besonderhede oor voortgaande oproepe op jou toestel te sien, en hierdie oproepe te beheer."</string>
+ <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+ <skip />
+ <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+ <skip />
<string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"lees seluitsending-boodskappe"</string>
<string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Laat die program toe om seluitsending-boodskappe te lees wat deur jou toestel ontvang word. Seluitsending-waarskuwings word in sommige plekke afgelewer om jou van noodsituasies te waarsku. Kwaadwillige programme mag inmeng met die prestasie of die werking van jou toestel wanneer \'n noodgeval se seluitsending ontvang word."</string>
<string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"lees ingetekende nuus"</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 47d2da0..e91fe9d 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -370,6 +370,10 @@
<string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"የሕዋስ ስርጭት መልዕክቶች እንደመጡ ለማስተላለፍ መተግበሪያው ከሕዋስ ስርጭት ሞዱሉ ጋር እንዲተሳሰር ያስችለዋል። የሕዋስ ስርጭት ማንቂያዎች አስቸኳይ ሁኔታዎች ሲያጋጥሙ አንዳንድ አካባቢዎች ላይ የሚላኩ ናቸው። የሕዋስ ስርጭት ሲደርስ ተንኮል-አዘል መተግበሪያዎች በመሣሪያዎ አፈጻጸም ወይም አሰራር ላይ ጣልቃ ሊገቡ ይችላሉ።"</string>
<string name="permlab_manageOngoingCalls" msgid="281244770664231782">"በመካሄድ ላይ ያሉ ጥሪዎችን አስተዳድር"</string>
<string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"አንድ መተግበሪያ በመካሄድ ላይ ስላሉ ጥሪዎች ዝርዝሮችን እንዲመለከት ያስችለዋል።"</string>
+ <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+ <skip />
+ <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+ <skip />
<string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"የህዋስ ስርጭት መልዕክቶችን አንብብ"</string>
<string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"መሣሪያህ የህዋስ ስርጭት መልዕክቶች ሲቀበል መተግበሪያው እንዲያነበው ይፈቅድለታል። የህዋስ ስርጭት ማንቂያዎች አስቸኳይ ሁኔታዎች ሲያጋጥሙ አንዳንድ አካባቢዎች ላይ የሚላኩ ናቸው። የህዋስ ስርጭት ሲደርስ ተንኮል አዘል መተግበሪያዎች በመሣሪያህ አፈጻጸም ወይም አሰራር ላይ ጣልቃ ሊገቡ ይችላሉ።"</string>
<string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"የምዝገባ መግቦች አንበብ"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 4d6b92f..ae1f2aa 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -374,6 +374,10 @@
<string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"يسمح للتطبيق بالارتباط بوحدة البث الخلوي لإعادة توجيه رسائل البث الخلوي بينما يتم استقبالها. ويتم تسليم تنبيهات البث الخلوي في بعض المواقع لتحذيرك في حالات الطوارئ. ويمكن أن تؤثر التطبيقات الضارة على أداء الجهاز أو تشغيله عندما يتم تلقي بث خلوي في حالات الطوارئ."</string>
<string name="permlab_manageOngoingCalls" msgid="281244770664231782">"إدارة المكالمات الجارية"</string>
<string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"يسمح هذا الإذن للتطبيق بمعرفة تفاصيل المكالمات الجارية على جهازك والتحكّم فيها."</string>
+ <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+ <skip />
+ <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+ <skip />
<string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"قراءة رسائل بث الخلية"</string>
<string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"السماح للتطبيق بقراءة رسائل بث الخلية التي يتلقاها هذا الجهاز. يتم تسليم اشعارات بث الخلية في بعض المواقع لتحذيرك من حالات طارئة. يمكن أن تتداخل التطبيقات الضارة مع أداء أو تشغيل الجهاز عندما يتم تلقي بث خلية طارئ."</string>
<string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"قراءة الخلاصات المشتركة"</string>
diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml
index 94d355f..fd8082a 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -370,6 +370,10 @@
<string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"চেল সম্প্ৰচাৰ বাৰ্তাসমূহ লাভ কৰিলে সেইবোৰ ফৰৱাৰ্ড কৰিবলৈ এপ্টোক চেল সম্প্ৰচাৰ মডিউলটোৰ সৈতে সংযুক্ত হ\'বলৈ অনুমতি দিয়ে। আপোনাক জৰুৰীকালীন পৰিস্থিতিসমূহৰ বিষয়ে সতৰ্ক কৰিবলৈ কিছুমান অৱস্থানত চেল সম্প্ৰচাৰ সতৰ্কবাৰ্তাসমূহ ডেলিভাৰ কৰা হয়। কোনো জৰুৰীকালীন চেল সম্প্ৰচাৰ লাভ কৰিলে ক্ষতিকাৰক এপ্সমূহে আপোনাৰ ডিভাইচটোৰ কাৰ্যক্ষমতা অথবা কাৰ্যপ্ৰণালীত হস্তক্ষেপ কৰিব পাৰে।"</string>
<string name="permlab_manageOngoingCalls" msgid="281244770664231782">"চলি থকা কলসমূহ পৰিচালনা কৰক"</string>
<string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"এটা এপক আপোনাৰ ডিভাইচত চলি থকা কলৰ সবিশেষ চাবলৈ আৰু এই কলসমূহ নিয়ন্ত্ৰণ কৰিবলৈ অনুমতি দিয়ে।"</string>
+ <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+ <skip />
+ <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+ <skip />
<string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"চেল সম্প্ৰচাৰৰ বার্তাবোৰ পঢ়ক"</string>
<string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"আপোনাৰ ডিভাইচে লাভ কৰা চেল সম্প্ৰচাৰৰ বার্তাবোৰ পঢ়িবলৈ এপক অনুমতি দিয়ে। আপোনাক জৰুৰীকালীন পৰিস্থিতিবোৰত সর্তক কৰিবলৈ চেল সম্প্ৰচাৰৰ বার্তাবোৰ প্ৰেৰণ কৰা হয়। জৰুৰীকালীন চেল সম্প্ৰচাৰ লাভ কৰাৰ সময়ত আপোনাৰ ডিভাইচৰ কাৰ্যদক্ষতা বা কাৰ্যপ্ৰণালীত ক্ষতিকাৰক এপবোৰে হস্তক্ষেপ কৰিব পাৰে।"</string>
<string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"আপুনি সদস্যভুক্ত হোৱা ফীডসমূহ পঢ়ক"</string>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index 633f6de..a14725b 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -370,6 +370,10 @@
<string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Tətbiqə şəbəkə yayım mesajlarını əldə edildiyi anda yönləndirmək üçün şəbəkə yayımı moduluna bağlanmaq icazəsi verir. Şəbəkə yayımı bəzi məkanlarda olan fövqəladə hadisələrlə bağlı Sizi xəbərdar etmək üçün qəbul edilir. Zərərli tətbiqlər fövqəladə şəbəkə yayımı əldə edildiyi zaman cihazın performansına və əməliyyatına müdaxilə edə bilər."</string>
<string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Davam edən zəngləri idarə edin"</string>
<string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Tətbiqə cihazınızda davam edən zənglər haqqında məlumatları görmək və bu zəngləri idarə etmək imkanı verir."</string>
+ <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+ <skip />
+ <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+ <skip />
<string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"mobil yayım mesajlarını oxuyur"</string>
<string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Tətbiqə telefonunuz tərəfindən alınmış yayım mesajlarını oxuma icazəsi verir. Telefon yayımı bəzi məkanlarda olan fövqəladə hadisələrlə bağlı sizi xəbərdar etmək üçün qəbul edilir. Zərərli tətbiqlər təcili mobil yayım qəbul edildiyi zaman telefonunun performansına və əməliyyatına müdaxilə edə bilər."</string>
<string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"abunə olunmuş xəbərləri oxuyur"</string>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index 8387984..91b5b045 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -371,6 +371,10 @@
<string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Dozvoljava aplikaciji da se vezuje za modul poruka za mobilne uređaje na lokalitetu da bi prosleđivala poruke za mobilne uređaje na lokalitetu onako kako su primljene. Obaveštenja poruka za mobilne uređaje na lokalitetu se na nekim lokacijama primaju kao upozorenja na hitne slučajeve. Zlonamerne aplikacije mogu da utiču na performanse ili ometaju rad uređaja kada se primi poruka o hitnom slučaju za mobilne uređaje na lokalitetu."</string>
<string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Upravljanje odlaznim pozivima"</string>
<string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Omogućava aplikaciji da vidi detalje o odlaznim pozivima na uređaju i da kontroliše te pozive."</string>
+ <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+ <skip />
+ <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+ <skip />
<string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"čitanje poruka info servisa"</string>
<string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Omogućava aplikaciji da čita poruke info servisa koje uređaj prima. Upozorenja info servisa se na nekim lokacijama primaju kao upozorenja na hitne slučajeve. Zlonamerne aplikacije mogu da utiču na performanse ili ometaju funkcionisanje uređaja kada se primi poruka info servisa o hitnom slučaju."</string>
<string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"čitanje prijavljenih fidova"</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index 42c50103..68b89f0 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -372,6 +372,10 @@
<string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Дазваляе праграме звязвацца з модулем сотавай трансляцыі, каб пераадрасоўваць атрыманыя там паведамленні. Абвесткі сотавай трансляцыі дасылаюцца ў некаторыя месцы, каб папярэджваць вас пра надзвычайныя сітуацыі. Шкодныя праграмы могуць негатыўна ўплываць на прадукцыйнасць або працу прылады падчас атрымання паведамленняў сотавай трансляцыі пра надзвычайныя сітуацыі."</string>
<string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Кіраваць уваходнымі выклікамі"</string>
<string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Дазваляе праграме праглядаць на прыладзе падрабязныя звесткі пра ўваходныя выклікі і кіраваць імі."</string>
+ <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+ <skip />
+ <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+ <skip />
<string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"чытаць паведамленні базавай станцыі"</string>
<string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Дазваляе прыкладанню чытаць паведамленні базавай станцыі, атрыманыя прыладай. Папярэджанні базавай станцыі дасылаюцца ў некаторыя месцы, каб папярэдзіць вас аб надзвычайных сітуацыях. Шкоднасныя прыкладанні могуць уплываць на прадукцыйнасць ці працу прылады пры атрыманні паведамлення базавай станцыі аб надзвычайнай сітуацыі."</string>
<string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"чытаць падпісаныя каналы"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 181746e..e369102 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -370,6 +370,10 @@
<string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Разрешава на приложението да се обвърже с модула за клетъчно излъчване, за да препраща получените съобщения с клетъчно излъчване. Сигналите с клетъчно излъчване се получават на някои местоположения, за да ви предупредят за спешни случаи. Злонамерените приложения могат да възпрепятстват изпълнението или работата на устройството ви при получаване на такова спешно излъчване."</string>
<string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Управление на текущите обаждания"</string>
<string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Разрешава на приложението да вижда подробности за текущите обаждания на устройството ви и да ги управлява."</string>
+ <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+ <skip />
+ <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+ <skip />
<string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"четене на съобщения с клетъчно излъчване"</string>
<string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Разрешава на приложението да чете съобщения с клетъчно излъчване, получени от устройството ви. Сигналите с клетъчно излъчване се получават на някои местоположения, за да ви предупредят за спешни ситуации. Злонамерените приложения могат да възпрепятстват изпълнението или работата на устройството ви при получаване на такова спешно излъчване."</string>
<string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"четене на емисиите с абонамент"</string>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index 236fff5..ecbc6d5 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -370,6 +370,10 @@
<string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"সেল ব্রডকাস্ট মেসেজ পেলে এটি সেল ব্রডকাস্ট মডিউলের সাথে তা যুক্ত করে যাতে সেই মেসেজ ফরওয়ার্ড করা যায়। আপনাকে জরুরি অবস্থা সম্পর্কে সাবধান করতে কিছু লোকেশনে সেল ব্রডকাস্ট অ্যালার্ট মেসেজ ডেলিভার করা হয়। জরুরি সেল ব্রডকাস্ট পাওয়া গেলে ক্ষতিকারক অ্যাপ আপনার ডিভাইসের পারফর্ম্যান্স ও অপারেশনে বাধা সৃষ্টি করতে পারে।"</string>
<string name="permlab_manageOngoingCalls" msgid="281244770664231782">"অনগোয়িং কল ম্যানেজ করুন"</string>
<string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"আপনার ডিভাইসে অনগোয়িং কলের বিষয়ে বিবরণ দেখতে এবং এই কলগুলি কন্ট্রোল করার জন্য অ্যাপকে অনুমতি দেয়।"</string>
+ <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+ <skip />
+ <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+ <skip />
<string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"সেল সম্প্রচার মেসেজ পড়ুন"</string>
<string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"আপনার ডিভাইস দ্বারা প্রাপ্ত সেল সম্প্রচার পড়তে অ্যাপ্লিকেশানটিকে অনুমতি দেয়৷ কয়েকটি স্থানে আপনাকে জরুরি অবস্থার জন্য সতর্ক করতে জরুরি সতর্কতাগুলি বিতরণ করা হয়৷ যখন একটি জরুরি সেল সম্প্রচার প্রাপ্ত হয় তখন ক্ষতিকারক অ্যাপ্লিকেশানগুলি আপনার ডিভাইসের কার্য সম্পাদনা বা কার্যকলাপে প্রতিবন্ধকতার সৃষ্টি করতে পারে৷"</string>
<string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"গ্রাহক হিসেবে নেওয়া ফিডগুলি পড়ে"</string>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index 1da2604..5088911 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -371,6 +371,10 @@
<string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Dopušta aplikaciji da se veže za modul info servisa kako bi prosljeđivala poruke info servisa. Upozorenja koja emitira info servis se isporučuju na nekim lokacijama kako bi vas upozorila na vanredne situacije. Zlonamjerne aplikacije mogu ometati performanse ili rad vašeg uređaja kada primite informacije o vanrednoj situaciji od info servisa."</string>
<string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Upravljanje pozivima u toku"</string>
<string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Omogućava aplikaciji da vidi detalje o pozivima u toku na vašem uređaju i da ih kontrolira."</string>
+ <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+ <skip />
+ <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+ <skip />
<string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"čitanje poruka info servisa"</string>
<string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Omogućava aplikaciji čitanje poruka info servisa koje je primio vaš uređaj. Upozorenja koja emitira info servis se isporučuju na nekim lokacijama kako bi vas upozorila na vanredne situacije. Zlonamjerne aplikacije mogu ometati performanse ili rad vašeg uređaja kada primite informaciju o vanrednoj situaciji od info servisa."</string>
<string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"čitanje sadržaja na koje ste pretplaćeni"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 867a34d..1719d53 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -371,6 +371,10 @@
<string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Permet que l\'aplicació es vinculi al mòdul de difusió mòbil per poder reenviar els missatges de difusió mòbil a mesura que es reben. Les alertes de difusió mòbil s\'entreguen en algunes ubicacions per alertar de situacions d\'emergència. És possible que les aplicacions malicioses interfereixin en el rendiment o en el funcionament del dispositiu quan es rebi una difusió mòbil d\'emergència."</string>
<string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Gestiona les trucades en curs"</string>
<string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Permet que una aplicació vegi els detalls sobre les trucades en curs al dispositiu i que controli aquestes trucades."</string>
+ <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+ <skip />
+ <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+ <skip />
<string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"llegir missatges de difusió mòbil"</string>
<string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Permet que l\'aplicació llegeixi missatges de difusió mòbil rebuts pel dispositiu. Les alertes de difusió mòbil s\'entreguen en algunes ubicacions per alertar de situacions d\'emergència. És possible que les aplicacions malicioses interfereixin en el rendiment o en el funcionament del dispositiu quan es rep una difusió mòbil d\'emergència."</string>
<string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"llegir els feeds als quals esteu subscrit"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 2c17373..d50f4f8 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -372,6 +372,10 @@
<string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Umožňuje aplikaci vytvořit vazbu s modulem informačních služeb za účelem přesměrovávání přijatých zpráv informačních služeb. Výstražná upozornění informačních služeb jsou v některých oblastech odesílána za účelem varování před výjimečnými událostmi. Škodlivé aplikace mohou narušit výkon či provoz vašeho zařízení během přijímání zpráv informačních služeb."</string>
<string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Správa probíhajících hovorů"</string>
<string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Umožňuje aplikaci zobrazit podrobnosti o probíhajících hovorech v zařízení a tyto hovory ovládat."</string>
+ <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+ <skip />
+ <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+ <skip />
<string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"čtení zpráv informačních služeb"</string>
<string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Umožňuje aplikaci číst zprávy informačních služeb přijaté ve vašem zařízení. Výstražná upozornění informačních služeb jsou v některých oblastech odesílána za účelem varování před výjimečnými událostmi. Škodlivé aplikace mohou narušit výkon či provoz vašeho zařízení během přijímání zpráv informačních služeb."</string>
<string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"čtení zdrojů přihlášených k odběru"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index f04fd75..e0fc3ca 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -370,6 +370,10 @@
<string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Tillader, at appen bindes til Cell Broadcast-modulet, så Cell Broadcast-meddelelser kan videresendes, når de modtages. I regioner sendes der Cell Broadcast-underretninger for at advare dig om nødsituationer. Ondsindede apps kan forstyrre effektiviteten eller driften af din enhed, når den modtager en Cell Broadcast-meddelelse om en nødsituation."</string>
<string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Administrere igangværende opkald"</string>
<string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Giver appen tilladelse til at se oplysninger om igangværende opkald på din enhed og styre disse opkald."</string>
+ <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+ <skip />
+ <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+ <skip />
<string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"læse Cell Broadcast-meddelelser"</string>
<string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Tillader, at appen læser Cell Broadcast-underretninger, der modtages af din enhed. I regioner sendes der Cell Broadcast-underretninger for at advare om nødsituationer. Ondsindede apps kan forstyrre ydelsen eller driften af din enhed, når der modtages en Cell Broadcast-meddelelse om en nødsituation."</string>
<string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"læse feeds, jeg abonnerer på"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index d55ba9f..7f0dd1e 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -370,6 +370,10 @@
<string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Ermöglicht der App, sich mit dem Cell-Broadcast-Modul zu verbinden, um empfangene Cell-Broadcast-Nachrichten weiterzuleiten. Cell-Broadcast-Benachrichtigungen können in einigen Ländern oder Regionen gesendet werden, um dich bei Notfallsituationen zu warnen. Schädliche Apps können die Leistung oder den Betrieb deines Geräts beeinträchtigen, wenn eine Cell-Broadcast-Notfallbenachrichtigung eingeht."</string>
<string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Aktuelle Anrufe verwalten"</string>
<string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Ermöglicht einer App, Details zu aktuellen Anrufen auf deinem Gerät zu sehen und diese Anrufe zu verwalten."</string>
+ <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+ <skip />
+ <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+ <skip />
<string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"Cell Broadcast-Nachrichten lesen"</string>
<string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Ermöglicht der App, von deinem Gerät empfangene Cell Broadcast-Nachrichten zu lesen. Cell Broadcast-Benachrichtigungen werden an einigen Standorten gesendet, um dich über Notfallsituationen zu informieren. Schädliche Apps können die Leistung oder den Betrieb deines Geräts beeinträchtigen, wenn eine Cell Broadcast-Notfallbenachrichtigung eingeht."</string>
<string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"Abonnierte Feeds lesen"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 1346faf..366533c 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -370,6 +370,10 @@
<string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Επιτρέπει στην εφαρμογή να συνδέεται στη λειτουργική μονάδα εκπομπής κινητής τηλεφωνίας, προκειμένου να προωθεί τα μηνύματα εκπομπής κινητής τηλεφωνίας κατά τη λήψη τους. Οι ειδοποιήσεις εκπομπής κινητής τηλεφωνίας προβάλλονται σε ορισμένες τοποθεσίες, για να σας προειδοποιήσουν σχετικά με καταστάσεις έκτακτης ανάγκης. Οι κακόβουλες εφαρμογές μπορεί να επηρεάσουν την απόδοση ή τη λειτουργία της συσκευής σας κατά τη λήψη μιας εκπομπής κινητής τηλεφωνίας έκτακτης ανάγκης."</string>
<string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Διαχείριση κλήσεων σε εξέλιξη"</string>
<string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Επιτρέπει σε μια εφαρμογή να βλέπει λεπτομέρειες σχετικά με τις κλήσεις σε εξέλιξη στη συσκευή σας και να τις ελέγχει."</string>
+ <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+ <skip />
+ <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+ <skip />
<string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"διαβάζει μηνύματα που έχουν μεταδοθεί μέσω κινητού τηλεφώνου"</string>
<string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Επιτρέπει στην εφαρμογή την ανάγνωση μηνυμάτων που έχουν μεταδοθεί μέσω κινητού τηλεφώνου και έχουν ληφθεί από τη συσκευή σας. Ειδοποιήσεις που μεταδίδονται μέσω κινητού παραδίδονται σε ορισμένες τοποθεσίες για να σας προειδοποιήσουν για καταστάσεις έκτακτης ανάγκης. Κακόβουλες εφαρμογές ενδέχεται να παρεμποδίσουν την απόδοση ή τη λειτουργία της συσκευής σας κατά τη λήψη μετάδοσης μέσω κινητού σχετικά με μια επείγουσα κατάσταση."</string>
<string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"διαβάζει ροές δεδομένων στις οποίες έχετε εγγραφεί"</string>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index 8f6bb19..4e54710 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -370,6 +370,10 @@
<string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Allows the app to bind to the cell broadcast module in order to forward cell broadcast messages as they are received. Cell broadcast alerts are delivered in some locations to warn you of emergency situations. Malicious apps may interfere with the performance or operation of your device when an emergency cell broadcast is received."</string>
<string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Manage ongoing calls"</string>
<string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Allows an app to see details about ongoing calls on your device and to control these calls."</string>
+ <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+ <skip />
+ <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+ <skip />
<string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"read mobile broadcast messages"</string>
<string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Allows the app to read mobile broadcast messages received by your device. Cell broadcast alerts are delivered in some locations to warn you of emergency situations. Malicious apps may interfere with the performance or operation of your device when an emergency mobile broadcast is received."</string>
<string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"read subscribed feeds"</string>
diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml
index 9129b82..4f3b52a 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -370,6 +370,8 @@
<string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Allows the app to bind to the cell broadcast module in order to forward cell broadcast messages as they are received. Cell broadcast alerts are delivered in some locations to warn you of emergency situations. Malicious apps may interfere with the performance or operation of your device when an emergency cell broadcast is received."</string>
<string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Manage ongoing calls"</string>
<string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Allows an app to see details about ongoing calls on your device and to control these calls."</string>
+ <string name="permlab_accessLastKnownCellId" msgid="7638226620825665130">"Access last known cell identity."</string>
+ <string name="permdesc_accessLastKnownCellId" msgid="6664621339249308857">"Allows an app to access to the last known cell identity provided by telephony."</string>
<string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"read cell broadcast messages"</string>
<string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Allows the app to read cell broadcast messages received by your device. Cell broadcast alerts are delivered in some locations to warn you of emergency situations. Malicious apps may interfere with the performance or operation of your device when an emergency cell broadcast is received."</string>
<string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"read subscribed feeds"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index dd7f4a7..240421b 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -370,6 +370,10 @@
<string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Allows the app to bind to the cell broadcast module in order to forward cell broadcast messages as they are received. Cell broadcast alerts are delivered in some locations to warn you of emergency situations. Malicious apps may interfere with the performance or operation of your device when an emergency cell broadcast is received."</string>
<string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Manage ongoing calls"</string>
<string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Allows an app to see details about ongoing calls on your device and to control these calls."</string>
+ <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+ <skip />
+ <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+ <skip />
<string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"read mobile broadcast messages"</string>
<string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Allows the app to read mobile broadcast messages received by your device. Cell broadcast alerts are delivered in some locations to warn you of emergency situations. Malicious apps may interfere with the performance or operation of your device when an emergency mobile broadcast is received."</string>
<string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"read subscribed feeds"</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index b652512..4b427bc 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -370,6 +370,10 @@
<string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Allows the app to bind to the cell broadcast module in order to forward cell broadcast messages as they are received. Cell broadcast alerts are delivered in some locations to warn you of emergency situations. Malicious apps may interfere with the performance or operation of your device when an emergency cell broadcast is received."</string>
<string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Manage ongoing calls"</string>
<string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Allows an app to see details about ongoing calls on your device and to control these calls."</string>
+ <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+ <skip />
+ <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+ <skip />
<string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"read mobile broadcast messages"</string>
<string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Allows the app to read mobile broadcast messages received by your device. Cell broadcast alerts are delivered in some locations to warn you of emergency situations. Malicious apps may interfere with the performance or operation of your device when an emergency mobile broadcast is received."</string>
<string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"read subscribed feeds"</string>
diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml
index 5ed9d11..66c24b4 100644
--- a/core/res/res/values-en-rXC/strings.xml
+++ b/core/res/res/values-en-rXC/strings.xml
@@ -370,6 +370,8 @@
<string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Allows the app to bind to the cell broadcast module in order to forward cell broadcast messages as they are received. Cell broadcast alerts are delivered in some locations to warn you of emergency situations. Malicious apps may interfere with the performance or operation of your device when an emergency cell broadcast is received."</string>
<string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Manage ongoing calls"</string>
<string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Allows an app to see details about ongoing calls on your device and to control these calls."</string>
+ <string name="permlab_accessLastKnownCellId" msgid="7638226620825665130">"Access last known cell identity."</string>
+ <string name="permdesc_accessLastKnownCellId" msgid="6664621339249308857">"Allows an app to access to the last known cell identity provided by telephony."</string>
<string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"read cell broadcast messages"</string>
<string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Allows the app to read cell broadcast messages received by your device. Cell broadcast alerts are delivered in some locations to warn you of emergency situations. Malicious apps may interfere with the performance or operation of your device when an emergency cell broadcast is received."</string>
<string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"read subscribed feeds"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index bc94eed..0d57e4b 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -371,6 +371,10 @@
<string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Permite que la app se vincule al módulo de emisión móvil para reenviar los mensajes de este tipo a medida que se reciben. En algunas ubicaciones, se envían alertas de emisión móvil para advertirte en situaciones de emergencia. Es posible que las apps maliciosas interfieran con el rendimiento o el funcionamiento de tu dispositivo cuando recibes una emisión móvil de emergencia."</string>
<string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Administrar llamadas en curso"</string>
<string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Permite que una app vea detalles sobre las llamadas en curso del dispositivo y las controle."</string>
+ <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+ <skip />
+ <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+ <skip />
<string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"Leer mensajes de difusión móvil"</string>
<string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Permite a la aplicación leer los mensajes de difusión móvil que recibe tu dispositivo. En algunas ubicaciones, las alertas de difusión móvil se envían para informar situaciones de emergencia. Las aplicaciones maliciosas pueden afectar el rendimiento o funcionamiento de tu dispositivo cuando se recibe un un mensaje de difusión móvil de emergencia."</string>
<string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"leer canales suscritos"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index c65e670..79be741 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -371,6 +371,10 @@
<string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Permite que la aplicación se vincule con el módulo de difusión móvil para reenviar los mensajes de ese tipo en cuanto se reciben. En ciertas ubicaciones se envían alertas de difusión móvil para avisar de situaciones de emergencia. Cuando se recibe una alerta de difusión móvil de emergencia, ciertas aplicaciones malintencionadas podrían interferir en el rendimiento o en el funcionamiento del dispositivo."</string>
<string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Gestionar llamadas en curso"</string>
<string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Permite que una aplicación consulte datos de llamadas que estén en curso en tu dispositivo y controle esas llamadas."</string>
+ <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+ <skip />
+ <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+ <skip />
<string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"leer mensajes de difusión móvil"</string>
<string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Permite que la aplicación lea mensajes de difusión móvil que haya recibido el dispositivo. Las alertas de difusión móvil se envían en algunas ubicaciones para avisar de situaciones de emergencia. Es posible que las aplicaciones malintencionadas interfieran en el rendimiento o en el funcionamiento del dispositivo si se recibe una alerta de difusión móvil de emergencia."</string>
<string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"leer feeds a los que está suscrito el usuario"</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 9c7cc1b..a07c4cd 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -370,6 +370,10 @@
<string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Võimaldab rakendusel luua ühenduse kärjeteadete mooduliga, et saabunud kärjeteateid edasi saata. Kärjeteateid edastatakse mõnes asukohas eriolukorrast teavitamiseks. Pahatahtlikud rakendused võivad seadme toimivust või tööd eriolukorra kärjeteate vastuvõtmisel segada."</string>
<string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Käimasolevate kõnede haldamine"</string>
<string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Võimaldab rakendusel näha teie seadmes käimasolevate kõnede üksikasju ja neid kõnesid hallata."</string>
+ <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+ <skip />
+ <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+ <skip />
<string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"mobiilsidesõnumite lugemine"</string>
<string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Võimaldab rakendusel lugeda seadme vastu võetud mobiilsidesõnumeid. Mobiilsidemärguandeid edastatakse mõnes asukohas eriolukorrast teavitamiseks. Pahatahtlikud rakendused võivad segada seadme toimivust või tööd eriolukorra sõnumi vastuvõtmisel."</string>
<string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"loe tellitud kanaleid"</string>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index 847fe56..b3f2ce2 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -370,6 +370,10 @@
<string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Sare mugikor bidezko iragarpen-modulura lotzeko baimena ematen dio aplikazioari, sare mugikor bidezko iragarpen-mezuak jaso ahala desbideratu ahal izateko. Sare mugikor bidezko iragarpen-alertak kokapen batzuetan entregatzen dira larrialdi-egoeren berri emateko. Sare mugikor bidezko larrialdi-iragarpenak jasotzean, asmo txarreko aplikazioek gailuaren errendimenduari edota funtzionamenduari eragin diezaiokete."</string>
<string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Kudeatu abian dauden deiak"</string>
<string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Gailuak jasotzen dituen deiei buruzko xehetasunak ikusteko eta dei horiek kontrolatzeko baimena ematen die aplikazioei."</string>
+ <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+ <skip />
+ <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+ <skip />
<string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"irakurri sare mugikor bidezko igorpen-mezuak"</string>
<string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Gailuak jasotako sare mugikor bidezko igorpen-mezuak irakurtzeko baimena ematen dio aplikazioari. Sare mugikor bidezko igorpen-alertak kokapen batzuetan ematen dira larrialdi-egoeren berri emateko. Asmo txarreko aplikazioek gailuaren errendimendua edo funtzionamendua oztopa dezakete larrialdi-igorpen horietako bat jasotzen denean."</string>
<string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"irakurri harpidetutako jarioak"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 6cdaf78a..7738e1c 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -370,6 +370,10 @@
<string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"به برنامه امکان میدهد به مدول پخش سلولی متصل شود تا پیامهای پخش سلولی را به محض دریافت بازارسال کند. هشدارهای پخش سلولی در برخی از موقعیتهای مکانی ارسال میشوند تا موقعیتهای اضطراری را به شما اعلام کنند. وقتی پخش سلولی دریافت میشود، ممکن است برنامههای مخرب در عملکرد یا کارکرد دستگاه شما اختلال ایجاد کنند."</string>
<string name="permlab_manageOngoingCalls" msgid="281244770664231782">"مدیریت تماسهای درحال انجام"</string>
<string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"به برنامه اجازه میدهد جزئیات تماسهای درحال انجام در دستگاه را ببیند و این تماسها را کنترل کند."</string>
+ <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+ <skip />
+ <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+ <skip />
<string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"خواندن پیامهای پخش سلولی"</string>
<string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"به برنامه اجازه میدهد پیامهای پخش سلولی دستگاه شما را بخواند. هشدارهای پخش سلولی در برخی از موقعیتهای مکانی تحویل داده میشوند تا موقعیتهای اضطراری را به شما اعلام کنند. وقتی پخش سلولی دریافت میشود، ممکن است برنامههای مخرب در عملکرد یا کارکرد دستگاه شما اختلال ایجاد کنند."</string>
<string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"خواندن فیدهای مشترک"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index e0dd50d..96e0ad4 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -370,6 +370,10 @@
<string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Sallii sovelluksen sitoutua solulähetysmoduuliin lähettääkseen solulähetysviestejä edelleen sitä mukaa kun ne saapuvat. Solulähetysilmoitusten avulla ilmoitetaan hätätilanteista joissakin paikoissa. Haitalliset sovellukset voivat häiritä laitteen toimintaa laitteen vastaanottaessa hätätilanteeseen liittyvän solulähetysviestin."</string>
<string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Ylläpidä käynnissä olevia puheluita"</string>
<string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Sovellus voi nähdä tietoja laitteella käynnissä olevista puheluista ja ohjata näitä puheluita."</string>
+ <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+ <skip />
+ <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+ <skip />
<string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"lue tiedotteita"</string>
<string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Antaa sovelluksen lukea laitteesi vastaanottamia tiedotteita. Tiedotteiden avulla ilmoitetaan hätätilanteista joissakin paikoissa. Haitalliset sovellukset voivat häiritä laitteen toimintaa laitteen vastaanottaessa hätätiedotteen."</string>
<string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"lukea tilattuja syötteitä"</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 0bb9ee5..379dce09 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -371,6 +371,10 @@
<string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Permet à l\'application d\'établir un lien avec le module de diffusion cellulaire afin de transférer les messages de diffusion cellulaire à mesure de leur réception. Dans certaines régions, des alertes de diffusion cellulaire sont envoyées afin de vous avertir de situations d\'urgence. Des applications malveillantes peuvent interférer avec les performances ou le fonctionnement de votre appareil lors de la réception d\'une alerte d\'urgence par diffusion cellulaire."</string>
<string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Gérer les appels en cours"</string>
<string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Autorise une application à afficher les renseignements concernant les appels en cours sur votre appareil et à les gérer."</string>
+ <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+ <skip />
+ <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+ <skip />
<string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"lire les messages de diffusion cellulaire"</string>
<string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Permet à l\'application de lire les messages de diffusion cellulaire que votre appareil reçoit. Dans certaines zones géographiques, des alertes vous sont envoyées afin de vous prévenir en cas de situation d\'urgence. Des applications malveillantes peuvent venir perturber les performances ou le fonctionnement de votre appareil lors de la réception d\'un message de diffusion cellulaire."</string>
<string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"lire les flux auxquels vous êtes abonné"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 8956904..455b2da 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -371,6 +371,10 @@
<string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Autorise l\'application à établir une connexion avec le module de diffusion cellulaire afin de transférer les messages reçus via un canal de diffusion cellulaire. Des alertes de diffusion cellulaire sont générées dans certaines régions afin de vous avertir de situations d\'urgence. Des applications malveillantes peuvent interférer avec les performances ou le fonctionnement de votre appareil lors de la réception d\'une alerte d\'urgence par diffusion cellulaire."</string>
<string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Gérer les appels en cours"</string>
<string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Autorise une application à afficher les détails concernant les appels en cours sur votre appareil et à contrôler ces appels."</string>
+ <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+ <skip />
+ <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+ <skip />
<string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"lire les messages reçus via un canal de diffusion cellulaire"</string>
<string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Permet à l\'application de lire les messages que votre appareil reçoit via un canal de diffusion cellulaire. Dans certaines zones géographiques, des alertes vous sont envoyées afin de vous prévenir en cas de situation d\'urgence. Les applications malveillantes peuvent venir perturber les performances ou le fonctionnement de votre appareil lorsqu\'un message est reçu via un canal de diffusion cellulaire."</string>
<string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"lire les flux auxquels vous êtes abonné"</string>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index b1598b3..df08dd3 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -370,6 +370,10 @@
<string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Permite que a aplicación se vincule ao módulo de difusión móbil para reenviar as mensaxes deste tipo segundo se reciban. As alertas de difusión móbil envíanse nalgunhas localizacións para avisar de situacións de emerxencia. As aplicacións maliciosas poden interferir no rendemento ou funcionamento do teu dispositivo cando se reciba unha difusión móbil de emerxencia."</string>
<string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Xestionar as chamadas saíntes"</string>
<string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Permite que unha aplicación controle as chamadas saíntes do teu dispositivo e consulte os detalles sobre elas."</string>
+ <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+ <skip />
+ <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+ <skip />
<string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"ler mensaxes de difusión móbil"</string>
<string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Permite á aplicación ler mensaxes de difusión móbil recibidas polo teu dispositivo. As alertas de difusión móbil envíanse nalgunhas localizacións para avisar de situacións de emerxencia. É posible que aplicacións maliciosas afecten ao rendemento ou funcionamento do teu dispositivo cando se recibe unha difusión móbil de emerxencia."</string>
<string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"ler feeds subscritos"</string>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index 023269f..574c510 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -370,6 +370,10 @@
<string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"સેલ બ્રોડકાસ્ટ સંદેશા પ્રાપ્ત થાય કે તરત ફૉરવર્ડ કરવા માટે સેલ બ્રોડકાસ્ટ મૉડ્યૂલ સાથે પ્રતિબદ્ધ થવા બાબતે ઍપને મંજૂરી આપે છે. તમને કટોકટીની પરિસ્થિતિની ચેતવણી આપવા માટે સેલ બ્રોડકાસ્ટ અલર્ટ અમુક સ્થાનોમાં ડિલિવર કરવામાં આવે છે. કટોકટી અંગેનો સેલ બ્રોડકાસ્ટ પ્રાપ્ત થાય, ત્યારે દુર્ભાવનાપૂર્ણ ઍપ તમારા ડિવાઇસના કાર્યપ્રદર્શન અથવા ઑપરેશનમાં વિક્ષેપ પાડે તેમ બની શકે છે."</string>
<string name="permlab_manageOngoingCalls" msgid="281244770664231782">"ચાલી રહેલા કૉલ મેનેજ કરો"</string>
<string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"ઍપને તમારા ડિવાઇસ પર ચાલુ કૉલ વિશેની વિગતો જોવાની અને આ કૉલને નિયંત્રિત કરવાની મંજૂરી આપે છે."</string>
+ <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+ <skip />
+ <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+ <skip />
<string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"સેલ બ્રોડકાસ્ટ સંદેશા વાંચો"</string>
<string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"ઍપ તમારા ડિવાઇસ દ્વારા પ્રાપ્ત થયેલ સેલ બ્રોડકાસ્ટ સંદેશાને વાંચવાની મંજૂરી આપે છે. સેલ બ્રોડકાસ્ટ ચેતવણીઓ તમને ઇમર્જન્સીની સ્થિતિઓ અંગે ચેતવવા માટે કેટલાક સ્થાનોમાં વિતરિત થાય છે. જ્યારે ઇમર્જન્સીનો સેલ બ્રોડકાસ્ટ પ્રાપ્ત થાય ત્યારે દુર્ભાવનાપૂર્ણ ઍપ તમારા ડિવાઇસના કાર્યપ્રદર્શન અથવા ઓપરેશનમાં હસ્તક્ષેપ કરી શકે છે."</string>
<string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"સબ્સ્ક્રાઇબ કરેલ ફીડ્સ વાંચો"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index a9221d8..2f08e2a 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -370,6 +370,10 @@
<string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"सेल ब्रॉडकास्ट (CBC) मैसेज आते ही उसे दूसरे नंबर पर भेजने के लिए, ऐप्लिकेशन को सेल ब्रॉडकास्ट (CBC) मॉड्यूल पर बाइंड करने की अनुमति देता है. कुछ जगहों में सेल ब्रॉडकास्ट (CBC) अलर्ट आपातकालीन स्थितियों के बारे में चेतावनी देने के लिए भेजा जाता है. नुकसान पहुंचाने वाले ऐप्लिकेशन, आपातकाल में सेल ब्रॉडकास्ट (CBC) मैसेज मिलने पर आपके डिवाइस के काम करते समय या इसके परफ़ॉर्मेंस में रुकावट पैदा कर सकते हैं."</string>
<string name="permlab_manageOngoingCalls" msgid="281244770664231782">"चल रहे कॉल प्रबंधित करें"</string>
<string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"इससे, ऐप्लिकेशन को आपके डिवाइस पर चल रहे कॉल की जानकारी देखने और उन्हें कंट्रोल करने की अनुमति मिलती है."</string>
+ <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+ <skip />
+ <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+ <skip />
<string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"सेल ब्रॉडकास्ट (CBC) मैसेज पढ़ें"</string>
<string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"ऐप को, वो सेल ब्रॉडकास्ट (CBC) मैसेज पढ़ने देता है जो आपके डिवाइस को मिले हैं. सेल ब्रॉडकास्ट (CBC) अलर्ट कुछ स्थानों (लोकेशन) पर आपको आपातकालीन स्थितियों की चेतावनी देने के लिए दिए जाते हैं. आपातकालीन सेल ब्रॉडकास्ट (CBC) मिलने पर, धोखा देने वाले ऐप आपके डिवाइस के परफ़ॉर्मेंस या कार्यवाही में दखल दे सकते हैं."</string>
<string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"सदस्यता वाली फ़ीड पढ़ें"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 43433a3..af3bd29 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -371,6 +371,10 @@
<string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Omogućuje aplikaciji da se poveže s modulom za emitiranje na mobitele kako bi prosljeđivala poruke koje se emitiraju na mobitele po njihovom primitku. Upozorenja značajke emitiranja na mobitele dostavljaju se na nekim lokacijama kako bi upozorila korisnike na hitne situacije. Zlonamjerne aplikacije mogu ometati izvršavanje ili rad vašeg uređaja kada stigne hitno emitiranje na mobitele."</string>
<string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Upravljanje tekućim pozivima"</string>
<string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Omogućuje aplikaciji pregled pojedinosti o tekućim pozivima na uređaju i upravljanje tim pozivima."</string>
+ <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+ <skip />
+ <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+ <skip />
<string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"čitaj poruke koje se emitiraju unutar mobilne mreže"</string>
<string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Omogućuje aplikaciji čitanje poruka emitiranih unutar mobilne mreže koje prima vaš uređaj. Upozorenja koja se emitiraju na području mobilne mreže dostavljaju se na nekim lokacijama kako bi upozorila korisnike na hitne situacije. Zlonamjerne aplikacije mogu ometati izvršavanje ili rad vašeg uređaja kada stigne hitno upozorenje koje se emitira unutar mobilne mreže."</string>
<string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"čitanje pretplaćenih feedova"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 64dee26..882156c 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -370,6 +370,10 @@
<string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Az alkalmazás összekapcsolódhat a cellán belüli üzenetszórás moduljával, hogy az érkezésükkor továbbítani tudja a cellán belüli üzeneteket. Bizonyos helyeken figyelmeztető üzeneteket kaphat a cellán belül a vészhelyzetekről. A rosszindulatú alkalmazások vészhelyzeti cellaüzenet érkezésekor befolyásolhatják az eszköz teljesítményét és működését."</string>
<string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Folyamatban lévő hívások kezelése"</string>
<string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Engedélyezi az alkalmazásnak, hogy az eszközén folyamatban lévő hívások részleteihez hozzáférjen, és vezérelje ezeket a hívásokat."</string>
+ <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+ <skip />
+ <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+ <skip />
<string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"cellán belüli üzenetek olvasása"</string>
<string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Lehetővé teszi az alkalmazás számára az eszközre érkező cellán belüli üzenetek olvasását. Bizonyos helyeken figyelmeztető üzeneteket kaphat a cellán belül a vészhelyzetekről. A rosszindulatú alkalmazások befolyásolhatják az eszköz teljesítményét vagy működését vészhelyzeti cellaüzenet érkezésekor."</string>
<string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"feliratkozott hírcsatornák olvasása"</string>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index 8a6d802..c85aeb8 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -370,6 +370,10 @@
<string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Թույլ է տալիս հավելվածին կապ հաստատել բջջային հեռարձակման մոդուլի հետ՝ բնակչությանը ծանուցող հաղորդագրությունները վերահասցեավորելու համար։ Որոշ երկրներում այս հաղորդագրություններն օգտագործվում են բնակչությանը արտակարգ իրավիճակների մասին զգուշացնելու համար: Վնասարար հավելվածները կարող են խանգարել ձեր սարքի աշխատանքին, որին ուղարկվում են այս հաղորդագրությունները:"</string>
<string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Ընթացիկ զանգերի կառավարում"</string>
<string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Թույլ է տալիս հավելվածին ձեր սարքում տեսնել ընթացիկ զանգերի մասին տեղեկությունները և կառավարել այդ զանգերը։"</string>
+ <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+ <skip />
+ <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+ <skip />
<string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"կարդալ բջջային զեկուցվող հաղորդագրությունները"</string>
<string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Թույլ է տալիս հավելվածին կարդալ ձեր սարքի կողմից ստացված բջջային հեռարձակվող հաղորդագրությունները: Բջջային հեռարձակվող զգուշացումները ուղարկվում են որոշ վայրերում` արտակարգ իրավիճակների մասին ձեզ զգուշացնելու համար: Վնասարար հավելվածները կարող են խանգարել ձեր սարքի արդյունավետությանը կամ շահագործմանը, երբ ստացվում է արտակարգ իրավիճակի մասին բջջային հաղորդում:"</string>
<string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"կարդալ բաժանորդագրված հոսքերը"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 991d69f..2b76815 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -370,6 +370,10 @@
<string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Mengizinkan aplikasi mem-binding ke modul cell broadcast untuk meneruskan pesan cell broadcast saat pesan tersebut diterima. Notifikasi cell broadcast dikirim di beberapa lokasi untuk memperingatkan Anda tentang situasi darurat. Aplikasi berbahaya dapat mengganggu performa atau operasi perangkat saat cell broadcast darurat diterima."</string>
<string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Mengelola panggilan yang sedang berlangsung"</string>
<string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Mengizinkan aplikasi untuk melihat detail panggilan yang sedang berlangsung di perangkat dan mengontrolnya."</string>
+ <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+ <skip />
+ <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+ <skip />
<string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"membaca pesan siaran seluler"</string>
<string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Mengizinkan aplikasi membaca pesan siaran seluler yang diterima perangkat Anda. Notifikasi siaran seluler dikirimkan di beberapa lokasi untuk memperingatkan Anda tentang situasi darurat. Aplikasi berbahaya dapat mengganggu kinerja atau operasi perangkat Anda saat siaran seluler darurat diterima."</string>
<string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"baca feed langganan"</string>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index 8bab2d7..f8b4197 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -370,6 +370,10 @@
<string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Heimilar forritinu að bindast endurvarpseiningunni til að framsenda skilaboð frá endurvarpa þegar þau berast. Viðvaranir frá endurvarpa berast á tilteknum stöðum til að vara þig við neyðarástandi. Spilliforrit geta truflað afköst eða virkni tækisins þegar neyðarboð berast frá endurvarpa."</string>
<string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Stjórna símtölum sem eru í gangi"</string>
<string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Leyfir forriti að sjá upplýsingar um og stjórna símtölum sem eru í gangi í tækinu þínu."</string>
+ <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+ <skip />
+ <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+ <skip />
<string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"lesa skilaboð frá endurvarpa"</string>
<string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Leyfir forriti að lesa skilaboð frá endurvarpa sem tækið móttekur. Viðvaranir frá endurvarpa berast á tilteknum stöðum til að vara þig við neyðarástandi. Spilliforrit geta truflað afköst eða virkni tækisins þegar neyðarboð berast frá endurvarpa."</string>
<string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"lesa strauma í áskrift"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index b2180ab..5a67476 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -371,6 +371,10 @@
<string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Consente all\'app di essere associata al modulo di cell broadcast al fine di inoltrare i messaggi di cell broadcast man mano che arrivano. Gli avvisi cell broadcast vengono trasmessi in alcune località per avvertire di situazioni di emergenza. Le app dannose potrebbero interferire con le prestazioni o con il funzionamento del dispositivo quando si riceve un messaggio cell broadcast di emergenza."</string>
<string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Gestione delle chiamate in corso"</string>
<string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Consente a un\'app di accedere a dettagli relativi alle chiamate in corso sul tuo dispositivo e di controllare tali chiamate."</string>
+ <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+ <skip />
+ <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+ <skip />
<string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"lettura di messaggi cell broadcast"</string>
<string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Consente all\'applicazione di leggere i messaggi cell broadcast ricevuti dal dispositivo. Gli avvisi cell broadcast vengono trasmessi in alcune località per avvertire di eventuali situazioni di emergenza. Le app dannose potrebbero interferire con le prestazioni o con il funzionamento del dispositivo quando si riceve un messaggio cell broadcast di emergenza."</string>
<string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"lettura feed sottoscritti"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 593668a..270568d 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -371,6 +371,10 @@
<string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"מאפשרת לאפליקציה להתחייב למודול של השידור הסלולרי כדי להעביר הודעות של שידור סלולרי כשהן מתקבלות. התראות שידור סלולרי נשלחות במקומות מסוימים כדי להזהיר אותך מפני מצבי חירום. אפליקציות זדוניות עשויות להפריע לביצועים או לפעולה של המכשיר כאשר מתקבל שידור חירום סלולרי."</string>
<string name="permlab_manageOngoingCalls" msgid="281244770664231782">"ניהול שיחות שנערכות"</string>
<string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"לאפליקציה תהיה אפשרות לראות פרטים על שיחות שנערכות במכשיר ולשלוט בשיחות האלה."</string>
+ <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+ <skip />
+ <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+ <skip />
<string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"קריאת הודעות שידור סלולרי"</string>
<string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"מאפשרת לאפליקציה לקרוא הודעות שידור סלולרי שהתקבלו במכשיר שלך. התראות שידור סלולרי נשלחות במקומות מסוימים כדי להזהיר אותך מפני מצבי חירום. אפליקציות זדוניות עשויות להפריע לביצועים או לפעולה של המכשיר שלך כאשר מתקבל שידור חירום סלולרי."</string>
<string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"קריאת עדכוני מינויים"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 3a904b6..98e2324 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -370,6 +370,10 @@
<string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"受信した緊急速報メールを転送するために、緊急速報メール モジュールにバインドすることをこのアプリに許可します。緊急速報メールは、緊急事態を警告する目的で一部の地域に配信されます。緊急速報メールの受信時に、悪意のあるアプリによってデバイスの動作や処理が妨害される恐れがあります。"</string>
<string name="permlab_manageOngoingCalls" msgid="281244770664231782">"通話の管理"</string>
<string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"デバイスでの通話に関する詳細の参照と、通話の操作をアプリに許可します。"</string>
+ <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+ <skip />
+ <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+ <skip />
<string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"緊急速報メール SMS の読み取り"</string>
<string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"デバイスで受信した緊急速報メール SMS の読み取りをアプリに許可します。緊急速報メールは、緊急事態を警告する目的で一部の地域に配信されます。緊急速報メールの受信時に、悪意のあるアプリによってデバイスの動作や処理が妨害される恐れがあります。"</string>
<string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"登録したフィードの読み取り"</string>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index e77068d..f7ce159 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -370,6 +370,10 @@
<string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"საშუალებას აძლევს აპს, დაუკავშირდეს cell broadcast მოდულს იმისთვის, რომ გადაამისამართოს cell broadcast შეტყობინებები მათი მიღებისთანავე. Cell broadcast გაფრთხილებები მიეწოდება ზოგიერთ მდებარეობაზე საგანგებო სიტუაციების შესახებ გაფრთხილების მიზნით. საგანგებო cell broadcast-ის მიღების დროს, მავნე აპებმა შეიძლება ხელი შეუშალონ თქვენი მოწყობილობის ფუნქციონირებას ან ოპერაციებს."</string>
<string name="permlab_manageOngoingCalls" msgid="281244770664231782">"მიმდინარე ზარების მართვა"</string>
<string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"საშუალებას აძლევს აპს, ნახოს თქვენს მოწყობილობაზე მიმდინარე ზარების დეტალები და აკონტროლოს ეს ზარები."</string>
+ <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+ <skip />
+ <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+ <skip />
<string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"მასიური დაგზავნის შეტყობინებების წაკითხვა"</string>
<string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"აპს შეეძლება, წაიკითხოს თქვენს მოწყობილობაზე გამოგზავნილი ქსელის სამაუწყებლო შეტყობინებები. სამაუწყებლო გაფრთხილებები მოგეწოდებათ ზოგიერთ ადგილზე ექსტრემალური სიტუაციების შესახებ გასაფრთხილებლად. ქსელის გადაუდებელი შეტყონიბენის მიღების დროს მავნე აპებმა შეიძლება ხელი შეუშალონ თქვენი მოწყობილობის ფუნქციონირებას ან ოპერაციებს."</string>
<string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"გამოწერილი არხების წაკითხვა"</string>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index e6af912..c459954 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -370,6 +370,10 @@
<string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Ұялы таратылым хабарлары алынғаннан кейін, олардың бағытын өзгерту үшін қолданбаға ұялы таратылым модулімен байланыстыруға мүмкіндік береді. Ұялы таратылым ескертулері кей аймақтарда төтенше жағдайлар туралы хабарлау үшін беріледі. Төтенше жағдай туралы ұялы таратылым хабары алынғаннан кейін, зиянды қолданбалар құрылғы жұмысына кедергі келтіруі мүмкін."</string>
<string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Қазіргі қоңырауларды басқару"</string>
<string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Қолданбаға құрылғыдағы қазіргі қоңыраулар туралы мәліметтерді көруге және басқаруға мүмкіндік береді."</string>
+ <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+ <skip />
+ <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+ <skip />
<string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"ұялы хабар тарату хабарларын оқу"</string>
<string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Қолданбаға ұялы таратылым хабарларын оқу мүмкіндігін береді. Ұялы таратылым дабылдары кейбір аймақтарда төтенше жағдай туралы ескерту үшін қолданылады. Төтенше ұялы хабарлар келгенде залалды қолданбалар құрылғының жұмысына кедергі жасауы мүмкін."</string>
<string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"жазылған ағындарды оқу"</string>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index 7133527..364db0c 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -370,6 +370,10 @@
<string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"អនុញ្ញាតឱ្យកម្មវិធីភ្ជាប់ទៅម៉ូឌុលការផ្សាយចល័ត ដើម្បីបញ្ជូនសារផ្សាយចល័តបន្ត នៅពេលទទួលបានសារទាំងនោះ។ ការជូនដំណឹងអំពីការផ្សាយចល័តត្រូវបានបញ្ជូនទៅទីតាំងមួយចំនួន ដើម្បីព្រមានអ្នកអំពីស្ថានភាពអាសន្ន។ កម្មវិធីគ្រោះថ្នាក់អាចរំខានដល់ដំណើរការ ឬប្រតិបត្តិការឧបករណ៍របស់អ្នក នៅពេលទទួលបានការផ្សាយចល័តពេលមានអាសន្ន។"</string>
<string name="permlab_manageOngoingCalls" msgid="281244770664231782">"គ្រប់គ្រងការហៅទូរសព្ទដែលកំពុងដំណើរការ"</string>
<string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"អនុញ្ញាតឱ្យកម្មវិធីមើលព័ត៌មានលម្អិតអំពីការហៅទូរសព្ទដែលកំពុងដំណើរការនៅលើឧបករណ៍របស់អ្នក និងគ្រប់គ្រងការហៅទូរសព្ទទាំងនេះ។"</string>
+ <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+ <skip />
+ <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+ <skip />
<string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"អានសារប្រកាសចល័ត"</string>
<string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"ឲ្យកម្មវិធីអានសារប្រកាសការហៅដែលឧបករណ៍របស់អ្នកបានទទួល។ ការជូនដំណឹងប្រកាសចល័តត្រូវបានបញ្ជូនទៅទីតាំងមួយចំនួន ដើម្បីព្រមានអ្នកអំពីស្ថានភាពអាសន្ន។ កម្មវិធីព្យាបាទអាចជ្រៀតជ្រែកការអនុវត្ត ឬប្រតិបត្តិការឧបករណ៍របស់អ្នកពេលទទួលការប្រកាសចល័តពេលអាសន្ន។"</string>
<string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"អានអត្ថបទព័ត៌មានបានជាវ"</string>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index 1e9414a..89e2361 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -370,6 +370,10 @@
<string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"ಸೆಲ್ ಪ್ರಸಾರವು ಸಂದೇಶಗಳನ್ನು ಸ್ವೀಕರಿಸಿದ ರೀತಿಯಲ್ಲಿಯೇ ಫಾರ್ವರ್ಡ್ ಮಾಡಲು, ಸೆಲ್ ಪ್ರಸಾರ ಮಾಡ್ಯುಲ್ ಅನ್ನು ಪ್ರತಿಬಂಧಿಸಲು ಆ್ಯಪ್ಗೆ ಅನುಮತಿಸುತ್ತದೆ. ಕೆಲವು ಸ್ಥಳಗಳಲ್ಲಿ ತುರ್ತು ಸ್ಥಿತಿಗಳ ಕುರಿತು ನಿಮಗೆ ಎಚ್ಚರಿಸಲು ಸೆಲ್ ಪ್ರಸಾರದ ಎಚ್ಚರಿಕೆಗಳನ್ನು ಕಳುಹಿಸಲಾಗುತ್ತದೆ. ತುರ್ತು ಸೆಲ್ ಪ್ರಸಾರವನ್ನು ಸ್ವೀಕರಿಸಿದಾಗ ನಿಮ್ಮ ಸಾಧನದ ಕಾರ್ಯಾಚರಣೆ ಅಥವಾ ಕಾರ್ಯಕ್ಷಮತೆಗೆ ದುರುದ್ದೇಶಪೂರಿತ ಆ್ಯಪ್ಗಳು ಹಸ್ತಕ್ಷೇಪ ಮಾಡಬಹುದು."</string>
<string name="permlab_manageOngoingCalls" msgid="281244770664231782">"ಚಾಲ್ತಿಯಲ್ಲಿರುವ ಕರೆಗಳನ್ನು ನಿರ್ವಹಿಸಿ"</string>
<string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"ನಿಮ್ಮ ಸಾಧನದಲ್ಲಿನ ಚಾಲ್ತಿಯಲ್ಲಿರುವ ಕರೆಗಳ ಕುರಿತಾದ ವಿವರಗಳನ್ನು ನೋಡಲು ಮತ್ತು ಆ ಕರೆಗಳನ್ನು ನಿಯಂತ್ರಿಸಲು ಆ್ಯಪ್ ಒಂದಕ್ಕೆ ಅನುಮತಿಸುತ್ತದೆ."</string>
+ <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+ <skip />
+ <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+ <skip />
<string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"ಸೆಲ್ ಪ್ರಸಾರದ ಸಂದೇಶಗಳನ್ನು ಓದಿರಿ"</string>
<string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"ನಿಮ್ಮ ಸಾಧನದಿಂದ ಸ್ವೀಕರಿಸಿದ ಸೆಲ್ ಪ್ರಸಾರ ಸಂದೇಶಗಳನ್ನು ರೀಡ್ ಮಾಡಲು ಅಪ್ಲಿಕೇಶನ್ಗೆ ಅನುಮತಿಸುತ್ತದೆ. ಸೆಲ್ ಪ್ರಸಾರ ಎಚ್ಚರಿಕೆಗಳನ್ನು ತುರ್ತು ಸಂದರ್ಭಗಳಲ್ಲಿ ನಿಮಗೆ ಎಚ್ಚರಿಸುವ ಸಲುವಾಗಿ ಕೆಲವು ಸ್ಥಳಗಳಲ್ಲಿ ವಿತರಿಸಲಾಗುತ್ತದೆ. ದುರುದ್ದೇಶಪೂರಿತ ಅಪ್ಲಿಕೇಶನ್ಗಳು ತುರ್ತು ಸೆಲ್ ಪ್ರಸಾರವನ್ನು ಸ್ವೀಕರಿಸುವಾಗ, ನಿಮ್ಮ ಸಾಧನದ ಕಾರ್ಯಕ್ಷಮತೆ ಇಲ್ಲವೇ ಕಾರ್ಯಾಚರಣೆಯಲ್ಲಿ ಹಸ್ತಕ್ಷೇಪ ಮಾಡಬಹುದು."</string>
<string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"ಚಂದಾದಾರ ಫೀಡ್ಗಳನ್ನು ಓದಿ"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index f78d0af..a129c9bb 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -370,6 +370,10 @@
<string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"셀 브로드캐스트 메시지를 수신하자마자 전달하기 위해 앱이 셀 브로드캐스트 모듈에 연결하도록 허용합니다. 비상 상황임을 알리기 위해 일부 지역에서 셀 브로드캐스트 경고가 전달됩니다. 비상 셀 브로드캐스트를 수신할 때 악성 앱이 기기의 성능이나 작동을 방해할 수 있습니다."</string>
<string name="permlab_manageOngoingCalls" msgid="281244770664231782">"진행 중인 전화 관리"</string>
<string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"앱에서 기기의 진행 중인 전화에 관한 세부정보를 확인하고 전화를 제어하도록 허용합니다."</string>
+ <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+ <skip />
+ <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+ <skip />
<string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"셀 브로드캐스트 메시지 읽기"</string>
<string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"앱이 기기가 수신한 셀 브로드캐스트 메시지를 읽을 수 있도록 합니다. 비상 상황임을 알리기 위해 일부 지역에서 셀 브로드캐스트 경고가 전달됩니다. 비상 셀 브로드캐스트를 수신할 때 악성 앱이 기기의 성능이나 작동을 방해할 수 있습니다."</string>
<string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"가입된 피드 읽기"</string>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index e7ee2e8..b84dcf5 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -370,6 +370,10 @@
<string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Уюк жөнөтүүлөрүнүн билдирүүлөрү келген сайын башка номерге багыттап туруу үчүн колдонмого уюк жөнөтүүлөрүнүн модулу менен байланышууга уруксат берет. Шашылыш уюк жөнөтүүлөрү кээ бир жерлердеги өзгөчө кырдаалдар тууралуу сизге эскертүү үчүн жөнөтүлөт. Зыянкеч колдонмолор шашылыш уюк жөнөтүүлөрү кабыл алынганда түзмөктүн майнаптуулугуна же иштешине жолтоо болушу мүмкүн."</string>
<string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Учурдагы чалууларды башкаруу"</string>
<string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Колдонмого телефонуңузда аткарылып жаткан чалууларды көрүп, аларды көзөмөлдөөгө уруксат берет."</string>
+ <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+ <skip />
+ <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+ <skip />
<string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"уюктук берүү билдирүүлөрүн окуу"</string>
<string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Колдонмого түзмөгүңүз кабыл алган уюк берүүнүн билдирүүлөрүн окууга жол берет. Шашылыш эскертүү билдирүүлөрү кээ бир жерлердеги өзгөчө кырдаалдар тууралу сизди эскертүү үчүн жөнөтүлөт. Зыяндуу колдономолор шашылыш эскертүүлөр берилип жатканда, сиздин түзмөктүн иштешине жолтоо болушу мүмкүн."</string>
<string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"жазылган түрмөктөрдү окуу"</string>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index 84fea73..267f60d 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -370,6 +370,10 @@
<string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"ອະນຸຍາດໃຫ້ແອັບຜູກມັດກັບໂມດູນການກະຈາຍສັນຍານໂທລະສັບເພື່ອສົ່ງຕໍ່ຂໍ້ຄວາມການກະຈາຍສັນຍານໂທລະສັບເມື່ອໄດ້ຮັບມາ. ການເຕືອນການກະຈາຍສັນຍານໂທລະສັບແມ່ນຖືກຈັດສົ່ງໃນບາງສະຖານທີ່ເພື່ອເຕືອນທ່ານໃນກໍລະນີມີເຫດການສຸກເສີນເກີດຂຶ້ນ. ແອັບທີ່ເປັນອັນຕະລາຍອາດລົບກວນປະສິດທິພາບ ຫຼື ການເຮັດວຽກຂອງອຸປະກອນທ່ານເມື່ອໄດ້ຮັບການກະຈາຍສັນຍານໂທລະສັບສຸກເສີນ."</string>
<string name="permlab_manageOngoingCalls" msgid="281244770664231782">"ຈັດການສາຍໂທອອກ"</string>
<string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"ອະນຸຍາດໃຫ້ແອັບໃດໜຶ່ງເບິ່ງເຫັນລາຍລະອຽດກ່ຽວກັບສາຍໂທອອກຢູ່ອຸປະກອນຂອງທ່ານ ແລະ ເພື່ອຄວບຄຸມການໂທເຫຼົ່ານີ້."</string>
+ <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+ <skip />
+ <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+ <skip />
<string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"ອ່ານຂໍ້ຄວາມກະຈາຍສັນຍານຂອງເສົາສັນຍານ"</string>
<string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"ອະນຸຍາດໃຫ້ແອັບຯ ສາມາດອ່ານຂໍ້ຄວາມແຈ້ງເຕືອນເຫດສຸກເສີນ ທີ່ໄດ້ຮັບໂດຍອຸປະກອນຂອງທ່ານ. ການແຈ້ງເຕືອນສຸກເສີນທີ່ມີໃຫ້ບໍລິການໃນບາງພື້ນທີ່ ເພື່ອແຈ້ງເຕືອນໃຫ້ທ່ານຮູ້ເຖິງສະຖານະການສຸກເສີນ. ແອັບພລິເຄຊັນທີ່ເປັນອັນຕະລາຍອາດລົບກວນປະສິດທິພາບ ຫຼືການດຳເນີນງານຂອງອຸປະກອນຂອງທ່ານ ເມື່ອໄດ້ການຮັບແຈ້ງເຕືອນສຸກເສີນຈາກສະຖານີມືຖື."</string>
<string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"ອ່ານຂໍ້ມູນຟີດທີ່ສະໝັກໄວ້"</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 0991daa..4696722 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -372,6 +372,10 @@
<string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Programai leidžiama susaistyti transliacijos mobiliuoju modulį, kad būtų galima persiųsti mobiliuoju transliuojamus pranešimus, kai jie gaunami. Transliacijos mobiliuoju įspėjimai pristatomi kai kuriose vietovėse, kad būtų galima įspėti apie kritines situacijas. Kai gaunamas mobiliuoju transliuojamas pranešimas apie kritinę situaciją, kenkėjiškos programos gali trukdyti įrenginiui veikti ar jį naudoti."</string>
<string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Tvarkyti vykstančius skambučius"</string>
<string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Programai leidžiama peržiūrėti išsamią informaciją apie vykstančius skambučius įrenginyje ir valdyti šiuos skambučius."</string>
+ <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+ <skip />
+ <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+ <skip />
<string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"skaityti mobiliuoju transliuojamus pranešimus"</string>
<string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Programai leidžiama skaityti mobiliuoju transliuojamus pranešimus, gaunamus jūsų įrenginyje. Mobiliuoju transliuojami įspėjimai pristatomi kai kuriose vietose, kad įspėtų apie kritines situacijas. Kai gaunamas mobiliuoju transliuojamas pranešimas apie kritinę situaciją, kenkėjiškos programos gali trukdyti įrenginiui veikti ar jį naudoti."</string>
<string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"skaityti prenumeruojamus tiekimus"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 68f496a..79e82cc 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -371,6 +371,10 @@
<string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Ļauj piesaistīt lietotni šūnu apraides modulim, lai pārsūtītu šūnu apraides ziņojumus, tiklīdz tie tiek saņemti. Šūnu apraides brīdinājumi tiek piegādāti noteiktās atrašanās vietās, lai brīdinātu jūs par ārkārtas situācijām. Ļaunprātīgas lietotnes var traucēt ierīces veiktspēju vai darbības, kad ir saņemts ārkārtas šūnas apraides ziņojums."</string>
<string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Aktīvo zvanu pārvaldība"</string>
<string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Ļauj lietotnei skatīt detalizētu informāciju par aktīvajiem zvaniem jūsu ierīcē, kā arī kontrolēt šos zvanus."</string>
+ <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+ <skip />
+ <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+ <skip />
<string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"šūnu apraides ziņojumu lasīšana"</string>
<string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Ļauj lietotnei lasīt ierīcē saņemtos šūnu apraides ziņojumus. Šūnu apraides brīdinājumi tiek piegādāti dažās atrašanās vietās, lai brīdinātu jūs par ārkārtas situācijām. Ļaunprātīgas lietotnes var traucēt ierīces veiktspēju vai darbības, kad ir saņemts ārkārtas šūnas apraides ziņojums."</string>
<string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"lasīt abonētās plūsmas"</string>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index 8828ab4..82cb889d 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -370,6 +370,10 @@
<string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Дозволува апликацијата да се врзе со модулот за мобилен пренос за да проследува пораки за мобилен пренос штом ќе се примат. Предупредувањата за мобилно емитување се доставуваат на некои локации за да ве предупредат на итни ситуации. Злонамерните апликации може да пречат во ефикасноста или работењето на вашиот уред кога се прима емитување за итен случај."</string>
<string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Управување со тековни повици"</string>
<string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Дозволува апликацијата да гледа детали за тековните повици на уредот и да ги контролира овие повици."</string>
+ <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+ <skip />
+ <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+ <skip />
<string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"прочитај пораки за мобилно емитување"</string>
<string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Овозможува апликациите да ги читаат пораките за мобилно емитување што ги прима вашиот уред. Предупредувањата за мобилно емитување се доставуваат на некои локации, за да ве предупредат на итни ситуации. Злонамерните апликации може да пречат во ефикасноста или работењето на вашиот уред кога се прима емитување за итен случај."</string>
<string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"читај претплатени навестувања на содржина"</string>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index cb0cb33..2bea784 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -370,6 +370,10 @@
<string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"സ്വീകരിക്കുന്ന മുറയ്ക്ക് ബ്രോഡ്കാസ്റ്റ് സന്ദേശങ്ങൾ കൈമാറുന്നതിന് സെൽ ബ്രോഡ്കാസ്റ്റ് മോഡ്യൂളിലേക്ക് ബൈൻഡ് ചെയ്യാൻ ആപ്പിനെ അനുവദിക്കുന്നു. അടിയന്തര സാഹചര്യങ്ങളെ കുറിച്ച് നിങ്ങൾക്ക് മുന്നറിയിപ്പ് നൽകുന്നതിന് ചില ലൊക്കേഷനുകളിൽ സെൽ ബ്രോഡ്കാസ്റ്റ് അലേർട്ടുകൾ ഡെലിവറി ചെയ്യപ്പെടുന്നു. ഒരു അടിയന്തര സെൽ ബ്രോഡ്കാസ്റ്റ് ലഭിക്കുമ്പോൾ ക്ഷുദ്രകരമായ അപ്ലിക്കേഷനുകൾ നിങ്ങളുടെ ഉപകരണത്തിന്റെ പ്രകടനത്തെയോ പ്രവർത്തനത്തെയോ തടസപ്പെടുത്താനിടയുണ്ട്."</string>
<string name="permlab_manageOngoingCalls" msgid="281244770664231782">"നടന്നുകൊണ്ടിരിക്കുന്ന കോളുകൾ മാനേജ് ചെയ്യുക"</string>
<string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"നിങ്ങളുടെ ഉപകരണത്തിൽ നടന്നുകൊണ്ടിരിക്കുന്ന കോളുകളുടെ വിശദാംശങ്ങൾ കാണാനും ഈ കോളുകൾ നിയന്ത്രിക്കാനും ആപ്പിനെ അനുവദിക്കുന്നു."</string>
+ <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+ <skip />
+ <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+ <skip />
<string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"സെൽ പ്രക്ഷേപണ സന്ദേശങ്ങൾ റീഡുചെയ്യുക"</string>
<string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"നിങ്ങളുടെ ഉപകരണത്തിൽ ലഭിച്ച സെൽ പ്രക്ഷേപണ സന്ദേശങ്ങൾ റീഡുചെയ്യാൻ അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു. അടിയന്തര സാഹചര്യങ്ങളെക്കുറിച്ച് നിങ്ങൾക്ക് മുന്നറിയിപ്പ് നൽകാനായി ചില ലൊക്കേഷനുകളിൽ നൽകപ്പെടുന്നവയാണ് സെൽ പ്രക്ഷേപണ അലേർട്ടുകൾ. ഒരു അടിയന്തര സെൽ പ്രക്ഷേപണം ലഭിക്കുമ്പോൾ, ക്ഷുദ്രകരമായ അപ്ലിക്കേഷനുകൾ നിങ്ങളുടെ ഉപകരണത്തിന്റെ പ്രകടനമോ പ്രവർത്തനമോ തടസ്സപ്പെടുത്താനിടയുണ്ട്."</string>
<string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"സബ്സ്ക്രൈബ് ചെയ്ത ഫീഡുകൾ വായിക്കുക"</string>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index 9bff0da..5d8f143 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -370,6 +370,10 @@
<string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Гар утсанд масс мессеж түгээх онцлогийн мессежийг хүлээн авах үед түүнийг шилжүүлэх зорилгоор аппад гар утсанд масс мессеж түгээх модультай холбогдохыг зөвшөөрөх Гар утсанд масс мессеж түгээх онцлогийн сэрэмжлүүлэг нь онцгой нөхцөл байдлын тухай танд анхааруулахын тулд зарим байршилд хүрдэг. Гар утсанд масс мессеж түгээх онцлогийн илгээх онцгой нөхцөл байдлын тухай мессежийг хүлээн авах үед хортой апп таны төхөөрөмжийн гүйцэтгэл эсвэл ажиллагаанд саад учруулж болзошгүй."</string>
<string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Үргэлжилж буй дуудлагыг удирдах"</string>
<string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Аппад таны төхөөрөмж дээрх үргэлжилж буй дуудлагын талаарх дэлгэрэнгүйг харах болон эдгээр дуудлагыг хянахыг зөвшөөрнө."</string>
+ <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+ <skip />
+ <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+ <skip />
<string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"үүрэн өргөн дамжууллын мессеж унших"</string>
<string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Апп нь таны төхөөрөмжийн хүлээн авсан үүрэн өргөн дамжуулах мессежийг унших боломжтой. Үүрэн өргөн дамжууллын мэдэгдэл нь яаралтай нөхцөл байдлыг анхааруулах зорилгоор зарим байршлуудад хүрдэг. Хортой апп нь яаралтай үүрэн өргөн дамжууллыг хүлээн авсан үед таны төхөөрөмжийн ажиллагаа болон чадамжид нөлөөлөх боломжтой."</string>
<string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"бүртгүүлсэн хангамжийг унших"</string>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index 4e55d1c..6654a14 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -370,6 +370,10 @@
<string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"सेल प्रसारण मेसेज मिळाल्यानंतर ते फॉरवर्ड करण्यासाठी ॲपला सेल प्रसारण मॉड्यूलमध्ये प्रतिबद्ध करण्याची अनुमती देते. काही स्थानांमध्ये तुम्हाला आणीबाणीच्या परिस्थीतींची चेतावणी देण्यासाठी सेल प्रसारण सूचना वितरित केल्या जातात. दुर्भावनापूर्ण अॅप्स आणीबाणी सेल प्रसारण मिळवतात तेव्हा ती तुमच्या डिव्हाइसच्या परफॉर्मन्समध्ये किंवा कामामध्ये कदाचित व्यत्यय आणू शकतात."</string>
<string name="permlab_manageOngoingCalls" msgid="281244770664231782">"सुरू असलेले कॉल व्यवस्थापित करा"</string>
<string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"ॲपला तुमच्या डिव्हाइसवर सुरू असलेल्या कॉलचे तपशील पाहण्याची आणि या कॉलना नियंत्रित करण्याची अनुमती द्या."</string>
+ <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+ <skip />
+ <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+ <skip />
<string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"सेल प्रसारण मेसेज वाचा"</string>
<string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"आपल्या डिव्हाइसद्वारे प्राप्त केलेले सेल प्रसारण मेसेज वाचण्यासाठी अॅप ला अनुमती देते. काही स्थानांमध्ये तुम्हाला आणीबाणीच्या परिस्थितीची चेतावणी देण्यासाठी सेल प्रसारण सूचना वितरीत केल्या जातात. आणीबाणी सेल प्रसारण प्राप्त होते तेव्हा आपल्या डिव्हाइसच्या कार्यप्रदर्शनात किंवा कार्यात दुर्भावनापूर्ण अॅप्स व्यत्यय आणू शकतात."</string>
<string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"सदस्यत्व घेतलेली फीड वाचा"</string>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index 45e3d91..d51dafe 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -370,6 +370,10 @@
<string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Membenarkan apl terikat pada modul siaran sel untuk mengirim semula mesej siaran sel apabila diterima. Makluman siaran sel dihantar di sesetengah lokasi untuk memberi amaran kepada anda tentang situasi kecemasan. Apl hasad boleh mengganggu prestasi atau operasi peranti anda apabila siaran sel kecemasan diterima."</string>
<string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Urus panggilan yang sedang berjalan"</string>
<string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Benarkan apl melihat butiran panggilan yang sedang berjalan pada peranti anda dan mengawal panggilan ini."</string>
+ <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+ <skip />
+ <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+ <skip />
<string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"baca mesej siaran sel"</string>
<string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Membolehkan apl membaca mesej siaran sel yang diterima oleh peranti anda. Isyarat siaran sel dihantar di beberapa lokasi untuk memberi amaran kepada anda tentang situasi kecemasan. Apl hasad boleh mengganggu prestasi atau operasi peranti anda apabila siaran sel kecemasan diterima."</string>
<string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"baca suapan langganan"</string>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index 6aee13e..a9726a5 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -370,6 +370,10 @@
<string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"စာတို ဖြန့်ဝေခြင်းစနစ် မော်ဂျူးကိုပေါင်းရန် အက်ပ်များအား ခွင့်ပြုသည်။ ၎င်းမှာ စာတို ဖြန့်ဝေခြင်းစနစ်သုံး မက်ဆေ့ဂျ်များကို လက်ခံရရှိသည့်အတိုင်း ထပ်ဆင့်ပို့ရန် ဖြစ်သည်။ အချို့တည်နေရာများတွင် သင့်အား အရေးပေါ်အခြေအနေများကို သတိပေးရန် စာတို ဖြန့်ဝေခြင်းစနစ်သုံး သတိပေးချက်များကို ပေးပို့သည်။ အရေးပေါ် စာတို ဖြန့်ဝေခြင်းကို ရရှိသည့်အခါ သံသယဖြစ်နိုင်ဖွယ်ရှိသည့် အက်ပ်များက သင့်စက်၏ စွမ်းဆောင်ရည်နှင့် အော်ပရေးရှင်းတို့ကို အနှောင့်အယှက်ပေးနိုင်သည်။"</string>
<string name="permlab_manageOngoingCalls" msgid="281244770664231782">"လက်ရှိခေါ်ဆိုမှုများကို စီမံခြင်း"</string>
<string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"သင့်စက်ပစ္စည်းပေါ်ရှိ လက်ရှိခေါ်ဆိုမှုများအကြောင်း အသေးစိတ်များကို ကြည့်ရှုရန်နှင့် ဤခေါ်ဆိုမှုများကို ထိန်းချုပ်ရန် အက်ပ်အား ခွင့်ပြုသည်။"</string>
+ <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+ <skip />
+ <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+ <skip />
<string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"စာတိုများ ဖြန့်ဝေခြင်းစနစ်အား ဖတ်ခြင်း"</string>
<string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"အပလီကေးရှင်းကို သင်၏ စက်ပစ္စည်းမှ လက်ခံရရှိသော အများလွှင့်ထုတ်ချက်များကို ဖတ်ရန် ခွင့်ပြုသည်။ အများလွှင့်ထုတ်ချက်များသည် အရေးပေါ်အခြေအနေများကို သင့်အား သတိပေးရန် အချို့ နေရာများတွင် ပို့ပေးသည်။ အရေးပေါ်သတိပေးချက် ထုတ်လွှင့်ချက်ကို လက်ခံရရှိချိန်တွင်အန္တရာယ် ဖြစ်စေနိုင်သော အပလီကေးရှင်းများသည် သင့်စက်ပစ္စည်း၏ လုပ်ငန်းလည်ပတ်မှုနှင့် စွမ်းဆောင်မှုကို ဝင်စွက်ဖက်နိုင်သည်။"</string>
<string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"အမည်သွင်းထားသောဖိဖ့်များကို ဖတ်ခြင်း"</string>
@@ -802,7 +806,7 @@
<string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"အစမြင်ကွင်း ခွင့်ပြုချက် အသုံးပြုမှု"</string>
<string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"အက်ပ်တစ်ခုအတွက် ခွင့်ပြုချက်စတင်အသုံးပြုမှုကို ကိုင်ဆောင်သူအား ခွင့်ပြုသည်။ ပုံမှန်အက်ပ်များအတွက် ဘယ်သောအခါမျှ မလိုအပ်ပါ။"</string>
<string name="permlab_startReviewPermissionDecisions" msgid="8690578688476599284">"ခွင့်ပြုသည့် ဆုံးဖြတ်ချက်များကို စတင်ကြည့်ခြင်း"</string>
- <string name="permdesc_startReviewPermissionDecisions" msgid="2775556853503004236">"ခွင့်ပြုထားသည့်အက်ပ်အား ခွင့်ပြုသည့်ဆုံးဖြတ်ချက်များကို ကြည့်နိုင်ရန်အတွက် စခရင်စတင်ရန် ခွင့်ပြုနိုင်သည်။ သာမန်အက်ပ်များအတွက် မည်သည့်အခါမျှ မလိုအပ်နိုင်ပါ။"</string>
+ <string name="permdesc_startReviewPermissionDecisions" msgid="2775556853503004236">"ခွင့်ပြုထားသည့်အက်ပ်အား ခွင့်ပြုသည့်ဆုံးဖြတ်ချက်များကို ကြည့်နိုင်ရန်အတွက် စခရင်စတင်ရန် ခွင့်ပြုနိုင်သည်။ သာမန်အက်ပ်များအတွက် မည်သည့်အခါမှ မလိုအပ်နိုင်ပါ။"</string>
<string name="permlab_startViewAppFeatures" msgid="7955084203185903001">"အက်ပ်ဝန်ဆောင်မှုများကို စတင်ကြည့်ခြင်း"</string>
<string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"ဝန်ဆောင်မှုအချက်အလက်ကိုများကို ခွင့်ပြုချက်ရထားသည့် အက်ပ်အား စတင်ကြည့်နိုင်ရန် ခွင့်ပြုသည်။"</string>
<string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"နမူနာနှုန်းမြင့်သော အာရုံခံစနစ်ဒေတာကို သုံးပါ"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 4965d90..822218d1 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -370,6 +370,10 @@
<string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Tillat at denne appen binder seg til modulen for kringkastede meldinger for å videresende kringkastede meldinger når de mottas. Kringkastede varsler leveres noen steder for å advare deg om nødssituasjoner. Skadelige apper kan forstyrre ytelsen eller funksjonen til enheten din når en kringkastet nødmelding mottas."</string>
<string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Administrer pågående anrop"</string>
<string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Gir en app tillatelse til å se informasjon om pågående anrop på enheten og til å kontrollere disse anropene."</string>
+ <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+ <skip />
+ <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+ <skip />
<string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"lese kringkastede meldinger"</string>
<string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Tillater at appen kan lese kringkastede meldinger enheten din mottar. Kringkastede varsler leveres noen steder for å advare deg om nødssituasjoner. Skadelige apper kan forstyrre ytelsen eller funksjonen til enheten din når en kringkastet nødmelding mottas."</string>
<string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"lese abonnement på nyhetskilder"</string>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index 7392276..de85e5c 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -370,6 +370,10 @@
<string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"मोबाइल प्रसारणसम्बन्धी म्यासेजहरू प्राप्त हुनासाथै तिनीहरूलाई फर्वार्ड गर्नका लागि यसले एपलाई मोबाइल प्रसारण मोड्युलमा जोडिने अनुमति दिन्छ। तपाईंलाई कतिपय स्थानमा आपत्कालीन अवस्थाका बारेमा जानकारी दिनका लागि मोबाइल प्रसारणसम्बन्धी अलर्टहरू पठाइन्छ। हानिकारक एपहरूले आपत्कालीन मोबाइल प्रसारण प्राप्त हुँदा तपाईंको यन्त्रलाई कार्य सम्पादन गर्ने वा सञ्चालित हुने क्रममा हस्तक्षेप गर्न सक्छन्।"</string>
<string name="permlab_manageOngoingCalls" msgid="281244770664231782">"जारी रहेका कलहरू व्यवस्थापन गर्न"</string>
<string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"तपाईं यो एपलाई अनुमति दिनुभयो यस एपले तपाईंको डिभाइसमा जारी रहेका कलसम्बन्धी विवरण हेर्न र ती कलहरू नियन्त्रण गर्न सक्छ।"</string>
+ <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+ <skip />
+ <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+ <skip />
<string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"सेल प्रसारित म्यासेजहरू पढ्नुहोस्"</string>
<string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"तपाईंको उपकरणद्वारा प्राप्त सेल प्रसारण म्यासेजहरू एपलाई पढ्न अनुमति दिन्छ। सेल प्रसारण चेतावनीहरू केही स्थानहरूमा तपाईंलाई आपत्कालीन गतिविधिहरूको बारेमा सचेत गराउन गरिएका छन्। खराब एपहरूले एउटा आपत्कालीन सेल प्रसारण प्राप्त गर्दछ जब तपाईंको उपकरणको प्रदर्शन वा अपरेशनको साथ हस्तक्षेप गर्न सक्दछन्।"</string>
<string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"सदस्य बनाइका फिडहरू पढ्नुहोस्"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index dd6f3a6..72a7e68 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -370,6 +370,10 @@
<string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Hiermee kan de app de module voor cell broadcasts binden om cell broadcast-berichten door te sturen als die worden ontvangen. Cell broadcast-waarschuwingen worden op bepaalde locaties verzonden om je te waarschuwen voor noodsituaties. Schadelijke apps kunnen de prestaties of verwerking van je apparaat verstoren als een bericht met een noodmelding wordt ontvangen."</string>
<string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Actieve gesprekken beheren"</string>
<string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Hiermee kan een app informatie over actieve gesprekken op je apparaat bekijken en deze gesprekken beheren."</string>
+ <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+ <skip />
+ <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+ <skip />
<string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"infodienstberichten lezen"</string>
<string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Toestaan dat de app infodienstberichten leest die worden ontvangen op je apparaat. Infodienstberichten worden verzonden naar bepaalde locaties om u te waarschjeen voor noodsituaties. Schadelijke apps kunnen de prestaties of verwerking van je apparaat verstoren wanneer een infodienstbericht wordt ontvangen."</string>
<string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"Geabonneerde feeds lezen"</string>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index bd4653b..1575fd8 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -370,6 +370,10 @@
<string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"ସେଲ୍ ପ୍ରସାରଣ ମେସେଜ୍ ପ୍ରାପ୍ତ ହେବା ପରେ ସେଗୁଡ଼ିକୁ ଫର୍ୱାର୍ଡ କରିବା ପାଇଁ ଆପ୍କୁ ସେଲ୍ ପ୍ରସାରଣ ମଡ୍ୟୁଲ୍ ସହିତ ସଂଯୁକ୍ତ କରିବାକୁ ଅନୁମତି ଦିଏ। ଜରୁରୀକାଳୀନ ପରିସ୍ଥିତିରେ ଆପଣଙ୍କୁ ଚେତାବନୀ ଦେବା ପାଇଁ କିଛି ଲୋକେସନ୍ରେ ସେଲ୍ ପ୍ରସାରଣ ଆଲର୍ଟ ବିତରଣ କରାଯାଇଥାଏ। ଏକ ଜରୁରୀକାଳୀନ ସେଲ୍ ପ୍ରସାରଣ ପ୍ରାପ୍ତ ହେବା ସମୟରେ କିଛି କ୍ଷତିକାରକ ଆପ୍ସ ହୁଏତ ଆପଣଙ୍କର ଡିଭାଇସ୍ର କାର୍ଯ୍ୟଦକ୍ଷତା କିମ୍ବା କାର୍ଯ୍ୟ ପ୍ରକ୍ରିୟାରେ ହସ୍ତକ୍ଷେପ କରିପାରେ।"</string>
<string name="permlab_manageOngoingCalls" msgid="281244770664231782">"ଚାଲୁଥିବା କଲଗୁଡ଼ିକୁ ପରିଚାଳନା କରନ୍ତୁ"</string>
<string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"ଏକ ଆପକୁ ଆପଣଙ୍କ ଡିଭାଇସରେ ଚାଲୁଥିବା କଲଗୁଡ଼ିକର ବିବରଣୀ ଦେଖିବା ଓ ଏହି କଲଗୁଡ଼ିକୁ ନିୟନ୍ତ୍ରଣ କରିବା ପାଇଁ ଅନୁମତି ଦେଇଥାଏ।"</string>
+ <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+ <skip />
+ <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+ <skip />
<string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"ସେଲ୍ ବ୍ରଡ୍କାଷ୍ଟ ମେସେଜ୍ ପଢ଼ନ୍ତୁ"</string>
<string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"ଆପଣଙ୍କ ଡିଭାଇସ୍ରେ ପ୍ରାପ୍ତ ହୋଇଥିବା ସେଲ୍ ବ୍ରଡ୍କାଷ୍ଟ ମେସେଜ୍ ପଢିବାକୁ ଆପ୍କୁ ଅନୁମତି ଦିଏ। ଜରୁରୀକାଳୀନ ଅବସ୍ଥା ବିଷୟରେ ଆପଣଙ୍କୁ ସତର୍କ କରାଇବାକୁ କିଛି ଲୋକେଶନ୍ରେ ସେଲ୍ ବ୍ରଡ୍କାଷ୍ଟ ସତର୍କ ଡେଲିଭର୍ କରାଯାଇଥାଏ। ଏକ ଜରୁରୀକାଳୀନ ସେଲ୍ ବ୍ରଡ୍କାଷ୍ଟ ପ୍ରାପ୍ତ ହେବାପରେ ହାନୀକାରକ ଆପ୍ ଆପଣଙ୍କ ଡିଭାଇସ୍ର କାର୍ଯ୍ୟକ୍ଷମତା କିମ୍ବା ସଞ୍ଚାଳନାରେ ବାଧା ପହଞ୍ଚାଇପାରନ୍ତି।"</string>
<string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"ସବସ୍କ୍ରାଇବ୍ ହୋଇଥିବା ଫୀଡ୍କୁ ପଢ଼ନ୍ତୁ"</string>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index f162344..01f4fe1 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -370,6 +370,10 @@
<string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"ਐਪ ਨੂੰ ਸੈੱਲ ਪ੍ਰਸਾਰਨ ਸੁਨੇਹਿਆਂ ਦੇ ਪ੍ਰਾਪਤ ਹੁੰਦੇ ਹੀ ਉਨ੍ਹਾਂ ਨੂੰ ਅੱਗੇ ਭੇਜਣ ਲਈ ਸੈੱਲ ਪ੍ਰਸਾਰਨ ਮਾਡਿਊਲ ਨਾਲ ਜੋੜਨ ਦੀ ਇਜਾਜ਼ਤ ਦਿੱਤੀ ਜਾਂਦੀ ਹੈ। ਸੈੱਲ ਪ੍ਰਸਾਰਨ ਅਲਰਟ ਤੁਹਾਨੂੰ ਐਮਰਜੈਂਸੀ ਸਥਿਤੀਆਂ ਦੀ ਚਿਤਾਵਨੀ ਦੇਣ ਲਈ ਕੁਝ ਟਿਕਾਣਿਆਂ \'ਤੇ ਪ੍ਰਦਾਨ ਕੀਤੀਆਂ ਜਾਂਦੀਆਂ ਹਨ। ਭੈੜੀਆਂ ਐਪਾਂ ਤੁਹਾਡੇ ਡੀਵਾਈਸ ਦੀ ਕਾਰਗੁਜ਼ਾਰੀ ਜਾਂ ਓਪਰੇਸ਼ਨ ਵਿੱਚ ਵਿਘਨ ਪਾ ਸਕਦੀਆਂ ਹਨ ਜਦੋਂ ਇੱਕ ਐਮਰਜੈਂਸੀ ਸੈੱਲ ਪ੍ਰਸਾਰਨ ਪ੍ਰਾਪਤ ਕੀਤਾ ਜਾਂਦਾ ਹੈ।"</string>
<string name="permlab_manageOngoingCalls" msgid="281244770664231782">"ਜਾਰੀ ਕਾਲਾਂ ਦਾ ਪ੍ਰਬੰਧਨ ਕਰੋ"</string>
<string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"ਐਪ ਨੂੰ ਆਪਣੇ ਡੀਵਾਈਸ \'ਤੇ ਜਾਰੀ ਕਾਲਾਂ ਬਾਰੇ ਵੇਰਵੇ ਦੇਖਣ ਅਤੇ ਇਹਨਾਂ ਕਾਲਾਂ ਨੂੰ ਕੰਟਰੋਲ ਕਰਨ ਦਿਓ।"</string>
+ <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+ <skip />
+ <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+ <skip />
<string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"ਸੈਲ ਪ੍ਰਸਾਰਨ ਸੁਨੇਹੇ ਪੜ੍ਹੋ"</string>
<string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"ਐਪ ਨੂੰ ਤੁਹਾਡੀ ਡੀਵਾਈਸ ਵੱਲੋਂ ਪ੍ਰਾਪਤ ਕੀਤੇ ਸੈੱਲ ਪ੍ਰਸਾਰਣ ਸੁਨੇਹੇ ਪੜ੍ਹਨ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ। ਸੈੱਲ ਪ੍ਰਸਾਰਣ ਚਿਤਾਵਨੀਆਂ ਤੁਹਾਨੂੰ ਸੰਕਟਕਾਲੀਨ ਸਥਿਤੀਆਂ ਦੀ ਚਿਤਾਵਨੀ ਦੇਣ ਲਈ ਕੁਝ ਨਿਰਧਾਰਤ ਟਿਕਾਣਿਆਂ ਤੇ ਪ੍ਰਦਾਨ ਕੀਤੀਆਂ ਜਾਂਦੀਆਂ ਹਨ। ਖਰਾਬ ਐਪਾਂ ਤੁਹਾਡੇ ਡੀਵਾਈਸ ਦੇ ਪ੍ਰਦਰਸ਼ਨ ਜਾਂ ਓਪਰੇਸ਼ਨ ਵਿੱਚ ਵਿਘਨ ਪਾ ਸਕਦੀਆਂ ਹਨ ਜਦੋਂ ਇੱਕ ਸੰਕਟਕਾਲੀਨ ਸੈੱਲ ਪ੍ਰਸਾਰਣ ਪ੍ਰਾਪਤ ਕੀਤਾ ਜਾਂਦਾ ਹੈ।"</string>
<string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"ਸਬਸਕ੍ਰਾਈਬ ਕੀਤੇ ਫੀਡਸ ਪੜ੍ਹੋ"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 7097503..375053e 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -372,6 +372,10 @@
<string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Zezwala aplikacji powiązać się z modułem komunikatów z sieci komórkowej, aby przekazywać je w momencie, w którym są otrzymywane. W niektórych lokalizacjach komunikaty alarmowe z sieci komórkowej są dostarczane, aby ostrzec Cię o sytuacjach zagrożenia. Złośliwe aplikacje mogą wpływać na działanie urządzenia lub zakłócać je po nadejściu komunikatu alarmowego z sieci komórkowej."</string>
<string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Zarządzaj połączeniami w toku"</string>
<string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Zezwala aplikacji zobaczyć detale dotyczące połączeń w toku na Twoim urządzeniu i na kontrolę tych połączeń."</string>
+ <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+ <skip />
+ <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+ <skip />
<string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"odczyt komunikatów z sieci komórkowej"</string>
<string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Zezwala aplikacji na odczyt komunikatów z sieci komórkowej odebranych na urządzeniu. Komunikaty alarmowe z sieci komórkowej są dostarczane w niektórych lokalizacjach w celu ostrzeżenia Cię o sytuacjach zagrożenia. Złośliwe aplikacje mogą wpływać na wydajność lub zakłócać działanie urządzenia po odebraniu komunikatu alarmowego z sieci komórkowej."</string>
<string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"czytanie subskrybowanych źródeł"</string>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index 49b4be9..9bec567 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -371,6 +371,10 @@
<string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Permite que o app se vincule ao módulo de transmissão celular para encaminhar mensagens de transmissão celular assim que elas forem recebidas. Alertas de transmissão celular são recebidos em alguns locais para avisar sobre situações de emergência. Apps maliciosos podem interferir no desempenho ou funcionamento do dispositivo quando uma transmissão celular de emergência é recebida."</string>
<string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Gerenciar chamadas em andamento"</string>
<string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Permite que um app veja detalhes sobre chamadas em andamento no seu dispositivo e as controle."</string>
+ <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+ <skip />
+ <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+ <skip />
<string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"ler mensagens de difusão celular"</string>
<string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Permite que o app leia mensagens de difusão celular recebidas por seu dispositivo. Alertas de difusão celular são recebidos em alguns locais para avisar você de situações de emergência. Apps maliciosos podem interferir no desempenho ou funcionamento de seu dispositivo quando uma difusão celular de emergência é recebida."</string>
<string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"ler feeds inscritos"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index f5fd19f..b1be29f 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -371,6 +371,10 @@
<string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Permite que a app se vincule ao módulo de difusão celular para encaminhar mensagens de difusão celular à medida que são recebidas. Os alertas de difusão celular são fornecidos em algumas localizações para avisar sobre situações de emergência. As aplicações maliciosas podem interferir com o desempenho ou funcionamento do seu dispositivo quando for recebida uma difusão celular de emergência."</string>
<string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Gerir chamadas em curso"</string>
<string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Permite que uma app veja detalhes acerca das chamadas em curso no seu dispositivo e controle essas chamadas."</string>
+ <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+ <skip />
+ <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+ <skip />
<string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"ler mensagens de transmissão celular"</string>
<string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Permite que a app leia mensagens de transmissão celular recebidas pelo seu dispositivo. Os alertas de transmissão celular são fornecidos em algumas localizações para avisá-lo sobre situações de emergência. As aplicações maliciosas podem interferir com o desempenho ou funcionamento do seu dispositivo quando for recebida uma transmissão celular de emergência."</string>
<string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"ler feeds subscritos"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 49b4be9..9bec567 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -371,6 +371,10 @@
<string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Permite que o app se vincule ao módulo de transmissão celular para encaminhar mensagens de transmissão celular assim que elas forem recebidas. Alertas de transmissão celular são recebidos em alguns locais para avisar sobre situações de emergência. Apps maliciosos podem interferir no desempenho ou funcionamento do dispositivo quando uma transmissão celular de emergência é recebida."</string>
<string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Gerenciar chamadas em andamento"</string>
<string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Permite que um app veja detalhes sobre chamadas em andamento no seu dispositivo e as controle."</string>
+ <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+ <skip />
+ <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+ <skip />
<string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"ler mensagens de difusão celular"</string>
<string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Permite que o app leia mensagens de difusão celular recebidas por seu dispositivo. Alertas de difusão celular são recebidos em alguns locais para avisar você de situações de emergência. Apps maliciosos podem interferir no desempenho ou funcionamento de seu dispositivo quando uma difusão celular de emergência é recebida."</string>
<string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"ler feeds inscritos"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index e34f989..b6029f7 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -371,6 +371,10 @@
<string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Permite aplicației să se conecteze la modulul de transmisie celulară pentru a redirecționa mesajele cu transmisie celulară pe măsură ce le primește. Alertele cu transmisie celulară sunt difuzate în unele locații pentru a te avertiza cu privire la situațiile de urgență. Aplicațiile rău intenționate pot afecta performanța sau funcționarea dispozitivului când e primită o transmisie celulară de urgență."</string>
<string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Să gestioneze apelurile în desfășurare"</string>
<string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Permite unei aplicații să vadă detalii despre apelurile în desfășurare de pe dispozitiv și să gestioneze apelurile respective."</string>
+ <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+ <skip />
+ <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+ <skip />
<string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"citește mesajele cu transmisie celulară"</string>
<string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Permite aplicației să citească mesajele primite prin transmisie celulară de dispozitiv. Alertele cu transmisie celulară sunt difuzate în unele locații pentru a te avertiza cu privire la situațiile de urgență. Aplicațiile rău intenționate pot afecta performanța sau funcționarea dispozitivului când e primită o transmisie celulară de urgență."</string>
<string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"citire feeduri abonat"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index d375179..7d3b869 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -372,6 +372,10 @@
<string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Приложение сможет выполнить привязку к модулю оповещения населения, чтобы пересылать сообщения широковещательных SMS-служб сразу после их получения. В некоторых странах эти сообщения используются для информирования об экстренных ситуациях. Вредоносное ПО может помешать работе устройства, на которое поступают такие сообщения."</string>
<string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Управление текущими звонками"</string>
<string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Приложение сможет управлять текущими звонками на вашем устройстве, а также получит доступ к сведениям о них"</string>
+ <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+ <skip />
+ <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+ <skip />
<string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"Читать сообщения массовой рассылки"</string>
<string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Приложение получит доступ к сообщениям широковещательных SMS-служб, которые в некоторых странах используются для информирования населения об экстренных ситуациях. Вредоносные программы могут помешать работе устройства, на которое поступают такие сообщения."</string>
<string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"Просмотр фидов пользователя"</string>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index c62fe33..12cb28a 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -370,6 +370,10 @@
<string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"සෙල් විකාශන පණිවිඩ ලැබුණු විට ඒවා යොමු කිරීම සඳහා සෙල් විකාශන මොඩියුලයට බැඳීමට යෙදුමට ඉඩ දෙයි. හදිසි අවස්ථා පිළිබඳව ඔබට අනතුරු ඇඟවීම සඳහා සෙල් විකාශන ඇඟවීම් සමහර ස්ථානවල ලබා දෙනු ලැබේ. හදිසි සෙල් විකාශනයක් ලැබෙන අවස්ථාවකදී, අනිෂ්ට යෙදුම්වලින් ඔබගේ උපාංග කාර්ය සාධනයට හෝ මෙහෙයුමට බාධා සිදු විය හැකිය."</string>
<string name="permlab_manageOngoingCalls" msgid="281244770664231782">"සිදු වෙමින් පවතින ඇමතුම් කළමනාකරණය කරන්න"</string>
<string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"ඔබගේ උපාංගයේ සිදු වෙමින් පවතින ඇමතුම් පිළිබඳ විස්තර බැලීමට සහ මෙම ඇමතුම් පාලනය කිරීමට යෙදුමකට ඉඩ දෙයි."</string>
+ <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+ <skip />
+ <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+ <skip />
<string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"සෙල් ප්රචාරණ පණිවිඩ කියවීම"</string>
<string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"ඔබගේ උපාංගයට ලැබුණු සෙල් විකාශන පණිවිඩ කියවීමට යෙදුමට අවසර දෙන්න. ඔබට හදිසි අවස්ථාවන් පිළිබඳ අනතුරු ඇඟවීමට සෙල් විකාශන පණිවිඩ ඇතැම් ස්ථානවල සිට යවනු ලබයි. හදිසි සෙල් විකාශන ලැබෙන අවස්ථාවකදී, අනිෂ්ට යෙදුම් මඟින් ඔබගේ උපාංගයට කාර්ය සාධනයට හෝ ක්රියකරණයට බාධා සිදුවිය හැක."</string>
<string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"දායක වූ සංග්රහ කියවීම"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 61ad94d..e2161ab 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -372,6 +372,10 @@
<string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Umožňuje aplikácii spojiť sa s modulom správ informačných služieb s cieľom preposielať prichádzajúce správy informačných služieb. Správy informačných služieb sa doručujú na určitých miestach a upozorňujú na tiesňové situácie. Škodlivé aplikácie môžu pri prijatí správy informačnej služby narušiť výkonnosť alebo prevádzku vášho zariadenia."</string>
<string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Správa prebiehajúcich hovorov"</string>
<string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Povolí aplikácii čítať podrobnosti o prebiehajúcich hovoroch v zariadení a ovládať ich."</string>
+ <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+ <skip />
+ <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+ <skip />
<string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"čítať správy informačných služieb"</string>
<string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Umožňuje aplikácii čítať správy informačných služieb prijaté vaším zariadením. Správy informačných služieb sa doručujú na určitých miestach a upozorňujú na tiesňové situácie. Škodlivé aplikácie môžu pri prijatí správy informačnej služby narušiť výkonnosť alebo prevádzku vášho zariadenia."</string>
<string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"čítať odoberané informačné kanály"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 79e0fa3..54cc786 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -372,6 +372,10 @@
<string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Aplikaciji omogoča povezovanje z modulom za oddaje v celici, da posreduje sporočila oddaj v celici, takoj ko jih prejme. Na nekaterih lokacijah so opozorila oddaj v celici dostavljena, da vas opozorijo na izredne razmere. Zlonamerne aplikacije lahko vplivajo na delovanje naprave, ko prejme sporočilo oddaje v celici."</string>
<string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Upravljanje aktivnih klicev"</string>
<string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Aplikaciji dovoljuje ogled podrobnosti o aktivnih klicih v napravi in upravljanje s temi klici."</string>
+ <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+ <skip />
+ <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+ <skip />
<string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"branje sporočil oddaje v celici"</string>
<string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Omogoča aplikaciji branje sporočil oddaje v celici, ki jih prejme naprava. Opozorila oddaje v celici so dostavljena na nekaterih lokacijah, da vas opozorijo na izredne razmere. Zlonamerne aplikacije lahko vplivajo na delovanje naprave, ko dobi sporočilo oddaje v celici."</string>
<string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"branje naročenih virov"</string>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index a160591..3bd5158 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -370,6 +370,10 @@
<string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Lejon që aplikacioni të lidhet me modulin e transmetimit celular për t\'i transferuar mesazhet e transmetimit celular menjëherë kur merren. Sinjalizimet e transmetimit celular dërgohen në disa vendndodhje për të të paralajmëruar për situata urgjente. Aplikacionet keqdashëse mund të ndërhyjnë në cilësinë e funksionimit ose në veprimin e pajisjes sate kur merret një transmetim celular urgjent."</string>
<string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Menaxho telefonatat në vazhdim"</string>
<string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Lejon që një aplikacion të shikojë detaje rreth telefonatave në vazhdim dhe t\'i kontrollojë këto telefonata."</string>
+ <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+ <skip />
+ <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+ <skip />
<string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"lexo mesazhet e transmetimit të qelizës"</string>
<string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Lejon aplikacionin të lexojë mesazhet e transmetimit të qelizës, të marra nga pajisja jote. Alarmet e transmetimit të qelizës dërgohen në disa vendndodhje për të të paralajmëruar në situata urgjente. Aplikacionet keqdashëse mund të ndërhyjnë në veprimtarinë ose operacionin e pajisjes tënde kur merret një transmetim urgjent i qelizës."</string>
<string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"lexo informacione të abonuara"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index e1f06de..0ea7b6e 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -371,6 +371,10 @@
<string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Дозвољава апликацији да се везује за модул порука за мобилне уређаје на локалитету да би прослеђивала поруке за мобилне уређаје на локалитету онако како су примљене. Обавештења порука за мобилне уређаје на локалитету се на неким локацијама примају као упозорења на хитне случајеве. Злонамерне апликације могу да утичу на перформансе или ометају рад уређаја када се прими порука о хитном случају за мобилне уређаје на локалитету."</string>
<string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Управљање одлазним позивима"</string>
<string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Омогућава апликацији да види детаље о одлазним позивима на уређају и да контролише те позиве."</string>
+ <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+ <skip />
+ <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+ <skip />
<string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"читање порука инфо сервиса"</string>
<string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Омогућава апликацији да чита поруке инфо сервиса које уређај прима. Упозорења инфо сервиса се на неким локацијама примају као упозорења на хитне случајеве. Злонамерне апликације могу да утичу на перформансе или ометају функционисање уређаја када се прими порука инфо сервиса о хитном случају."</string>
<string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"читање пријављених фидова"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index dc9c194..12e24b6 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -370,6 +370,10 @@
<string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Tillåter att appen binds till cellsändningsmodulen så att massutskick via sms kan vidarebefordras vid mottagandet. I vissa områden används massutskick via sms för att varna om nödsituationer. Skadliga appar kan påverka enhetens prestanda eller funktioner när ett massutskick via sms tas emot."</string>
<string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Hantera pågående samtal"</string>
<string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Tillåter att en app får åtkomst till information om pågående samtal på enheten och kan kontrollera dessa samtal."</string>
+ <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+ <skip />
+ <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+ <skip />
<string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"läsa SMS-meddelanden"</string>
<string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Appen tillåts läsa SMS som skickas till din enhet. På vissa platser skickas SMS för att varna för nödsituationer. Skadliga appar kan påverka enhetens prestanda eller funktionalitet när du får ett meddelande om en nödsituation via SMS."</string>
<string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"läsa flöden som du prenumererar på"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index c5979dd..4a99945 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -370,6 +370,10 @@
<string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Huruhusu programu ipachikwe katika sehemu ya matangazo ya simu ili isambaze ujumbe wa matangazo ya simu unapopokewa. Arifa za matangazo ya simu huwasilishwa katika maeneo mengine ili kukuonya juu ya hali za dharura. Huenda programu hasidi zikatatiza utendaji au shughuli ya kifaa chako matangazo ya simu ya dharura yanapopokewa."</string>
<string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Dhibiti simu zinazoendelea"</string>
<string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Huruhusu programu kuangalia maelezo kuhusu simu zinazoendelea kwenye kifaa chako na kuzidhibiti."</string>
+ <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+ <skip />
+ <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+ <skip />
<string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"soma mawasiliano ya matangazo ya simu"</string>
<string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Huruhusu programu kusoma mawasiliano ya matangazo ya simu yaliyoingia kwenye kifaa chako. Arifa za matangazo ya simu huwasilishwa katika maeneo mengine ili kukuonya juu ya hali za dharura. Huenda programu hasidi zikatatiza utendajikazi au shughuli ya kifaa chako wakati matangazo ya simu ya dharura yameingia."</string>
<string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"kusoma mipasho kutoka vyanzo unavyofuatilia"</string>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index 5017e14..20f12c4 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -370,6 +370,10 @@
<string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"செல் பிராட்காஸ்ட் மெசேஜ்களைப் பெறும்போதெல்லாம் அவற்றை முன்னனுப்பும் பொருட்டு, ஆப்ஸை செல் பிராட்காஸ்ட் மாடியூலோடு இணைக்கும். சில இடங்களில் அவசர சூழ்நிலைகளின் போது உங்களை எச்சரிக்க செல் பிராட்காஸ்ட் விழிப்பூட்டல்கள் அனுப்பப்படும். அவசரநிலை செல் பிராட்காஸ்ட்டைப் பெறும்போது, தீங்கிழைக்கும் ஆப்ஸ் உங்கள் சாதனத்தின் செயல்திறனுக்கோ செயல்பாட்டிற்கோ இடையூறு விளைவிக்கக்கூடும்."</string>
<string name="permlab_manageOngoingCalls" msgid="281244770664231782">"செயலில் உள்ள அழைப்புகளை நிர்வகித்தல்"</string>
<string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"உங்கள் சாதனத்தில், செயலில் உள்ள அழைப்புகள் குறித்த விவரங்களைப் பார்க்கவும் அந்த அழைப்புகளை நிர்வகிக்கவும் ஆப்ஸை அனுமதிக்கும்."</string>
+ <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+ <skip />
+ <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+ <skip />
<string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"செல் அலைபரப்புச் செய்திகளைப் படித்தல்"</string>
<string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"உங்கள் சாதனத்தில் பெறப்படும் செல் அலைபரப்புச் செய்திகளைப் படிப்பதற்குப் ஆப்ஸை அனுமதிக்கிறது. அவசரநிலை சூழ்நிலைகளை உங்களுக்கு எச்சரிக்கைச் செய்வதற்கு சில இடங்களில் செல் அலைபரப்பு விழிப்பூட்டல்கள் வழங்கப்படும். அவசரநிலை மொபைல் அலைபரப்புப் பெறப்படும்போது உங்கள் சாதனத்தின் செயல்திறன் அல்லது செயல்பாட்டுடன் தீங்கிழைக்கும் ஆப்ஸ் அதைத் தடுக்கலாம்."</string>
<string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"குழுசேர்ந்த ஊட்டங்களைப் படித்தல்"</string>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 624b2c9..ec58281 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -370,6 +370,10 @@
<string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"సెల్ ప్రసార మెసేజ్లను స్వీకరించినప్పుడు, వాటిని ఫార్వర్డ్ చేయడానికి సెల్ ప్రసార మాడ్యూల్కు కట్టుబడి ఉండేందుకు యాప్ను అనుమతిస్తుంది. ఎమర్జెన్సీ పరిస్థితుల గురించి మిమ్మల్ని హెచ్చరించడానికి కొన్ని లొకేషన్లలో సెల్ ప్రసార అలర్ట్లు డెలివరీ చేయబడతాయి. ఎమర్జెన్సీ సెల్ ప్రసార అలర్ట్ను స్వీకరించినప్పుడు హానికరమైన యాప్లు మీ పరికరం పనితీరుకు లేదా నిర్వహణకు ఆటంకం కలిగించే అవకాశం ఉంది."</string>
<string name="permlab_manageOngoingCalls" msgid="281244770664231782">"కొనసాగుతున్న కాల్స్ను మేనేజ్ చేయండి"</string>
<string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"మీ పరికరంలో కొనసాగుతున్న కాల్స్ను చూడటానికి అలాగే వాటిని కంట్రోల్ చేయడానికి ఒక యాప్కు అనుమతిస్తోంది."</string>
+ <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+ <skip />
+ <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+ <skip />
<string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"సెల్ ప్రసార మెసేజ్లను చదవడం"</string>
<string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"మీ పరికరం స్వీకరించిన సెల్ ప్రసార మెసేజ్లను చదవడానికి యాప్ను అనుమతిస్తుంది. ఎమర్జెన్సీ పరిస్థితుల గురించి మిమ్మల్ని హెచ్చరించడానికి కొన్ని లొకేషన్లలో సెల్ ప్రసార అలర్ట్లు డెలివరీ చేయబడతాయి. ఎమర్జెన్సీ సెల్ ప్రసార అలర్ట్ను స్వీకరించినప్పుడు హానికరమైన యాప్లు మీ పరికరం పనితీరుకు లేదా నిర్వహణకు ఆటంకం కలిగించే అవకాశం ఉంది."</string>
<string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"చందా చేయబడిన ఫీడ్లను చదవడం"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 1555984..0da6af7 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -370,6 +370,10 @@
<string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"อนุญาตให้แอปเชื่อมโยงกับโมดูลการส่งข้อมูลเตือนภัยทางมือถือ (CB) เพื่อส่งต่อข้อความจากการส่งข้อมูลเตือนภัยทางมือถือ (CB) ทันทีที่ได้รับ ระบบจะส่งการแจ้งเตือนจากการส่งข้อมูลเตือนภัยทางมือถือ (CB) ในบางตำแหน่งเพื่อแจ้งเตือนคุณเกี่ยวกับสถานการณ์ฉุกเฉิน แอปที่เป็นอันตรายอาจรบกวนประสิทธิภาพหรือการทำงานของอุปกรณ์เมื่อได้รับการส่งข้อมูลเตือนภัยทางมือถือ (CB) ในกรณีฉุกเฉิน"</string>
<string name="permlab_manageOngoingCalls" msgid="281244770664231782">"จัดการสายที่สนทนา"</string>
<string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"อนุญาตแอปเพื่อดูรายละเอียดเกี่ยวกับสายที่สนทนาอยู่บนโทรศัพท์และเพื่อควบคุมสายสนทนาเหล่านี้"</string>
+ <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+ <skip />
+ <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+ <skip />
<string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"อ่านข้อความที่ได้รับจากสถานีมือถือ"</string>
<string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"อนุญาตให้แอปอ่านข้อความจากสถานีมือถือที่อุปกรณ์ได้รับ การแจ้งเตือนทางมือถือมีให้บริการในบางพื้นที่ โดยจะแจ้งเตือนคุณเกี่ยวกับสถานการณ์ฉุกเฉิน แอปที่เป็นอันตรายอาจเข้าแทรกแซงการทำงานของอุปกรณ์เมื่อได้รับข้อความแจ้งเตือนฉุกเฉิน"</string>
<string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"อ่านฟีดข้อมูลที่สมัครไว้"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 25422a5..cf38312 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -370,6 +370,10 @@
<string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Nagbibigay-daan sa app na mag-bind sa module ng cell broadcast para makapagpasa ng mga mensahe ng cell broadcast pagkatanggap sa mga ito. Inihahatid ang mga alerto ng cell broadcast sa ilang lokasyon para balaan ka tungkol sa mga emergency na sitwasyon. Posibleng makasagabal ang mga nakakahamak na app sa performance o pagpapatakbo ng iyong device kapag nakatanggap ito ng emergency na cell broadcast."</string>
<string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Pamahalaan ang mga kasalukuyang tawag"</string>
<string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Pinapayagan ang app na makita ang mga detalye tungkol sa mga kasalukuyang tawag sa iyong device at kontrolin ang mga tawag na ito."</string>
+ <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+ <skip />
+ <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+ <skip />
<string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"basahin ang mga mensahe ng cell broadcast"</string>
<string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Binibigyang-daan ang app na magbasa ng mga mensahe ng cell broadcast na natanggap ng iyong device. Inihahatid ang mga alerto ng cell broadcast sa ilang lokasyon upang balaan ka tungkol sa mga emergency na sitwasyon. Maaaring makaabala ang nakakahamak na apps sa performance o pagpapatakbo ng iyong device kapag nakatanggap ng emergency na cell broadcast."</string>
<string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"magbasa ng mga na-subscribe na feed"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 64a150c..7751f62 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -370,6 +370,10 @@
<string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Uygulamanın hücre yayını mesajları geldiğinde bunları yönlendirmek için hücre yayını modülüne bağlanmasına izin verir. Hücre yayını uyarıları bazı konumlarda acil durumlar hakkında sizi uyarmak için kullanılır. Zararlı uygulamalar acil durum hücre yayını alındığında cihazınızın performansını ve çalışmasını olumsuz etkileyebilir."</string>
<string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Devam eden aramaları yönetme"</string>
<string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Uygulamanın, cihazınızda devam eden aramalarla ilgili bilgileri görüp kontrol etmesine izin verir."</string>
+ <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+ <skip />
+ <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+ <skip />
<string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"hücre yayını mesajlarını oku"</string>
<string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Uygulamaya, cihazınız tarafından alınan hücre yayını mesajlarını okuma izni verir. Hücre yayını uyarıları bazı yerlerde acil durumlar konusunda sizi uyarmak için gönderilir. Kötü amaçlı uygulamalar acil hücre yayını alındığında cihazınızın performansına ya da çalışmasına engel olabilir."</string>
<string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"abone olunan yayınları okuma"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 81fe67f..491956c 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -372,6 +372,10 @@
<string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Дозволяє додатку зв\'язуватися з модулем Cell Broadcast, щоб переадресувати відповідні вхідні повідомлення. У деяких місцеположеннях сповіщення Cell Broadcast надсилаються для попередження про надзвичайні ситуації. Після повідомлення Cell Broadcast шкідливі додатки можуть перешкоджати роботі вашого пристрою."</string>
<string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Керування поточними дзвінками"</string>
<string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Дає змогу додатку переглядати поточні дзвінки на пристрої та керувати ними."</string>
+ <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+ <skip />
+ <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+ <skip />
<string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"читати широкомовні повідомлення мережі"</string>
<string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Дозволяє програмі читати широкомовні повідомлення мережі, отримані пристроєм. Широкомовні сповіщення мережі надсилаються в деяких країнах для попередження про надзвичайні ситуації. Шкідливі програми можуть втручатися у швидкодію чи роботу пристрою під час отримання широкомовного повідомлення мережі про надзвичайну ситуацію."</string>
<string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"читати підписані канали"</string>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index 59461b8..c9346ea 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -370,6 +370,10 @@
<string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"سیل کی نشریاتی پیغامات کے موصول ہوتے ہی فارورڈ کرنے کے لیے ایپ کو سیل کے نشریاتی ماڈیول میں پابندی لگانے کی اجازت دیں۔ سیل کی نشریاتی الرٹس آپ کو ایمرجنسی حالات سے مطلع کرنے کیلئے کچھ مقامات میں مہیا کی جاتی ہیں۔ نقصان دہ ایپس کوئی ایمرجنسی سیل براڈ کاسٹ موصول ہونے پر آپ کے آلے کی کارکردگی یا عمل میں مداخلت کر سکتی ہیں۔"</string>
<string name="permlab_manageOngoingCalls" msgid="281244770664231782">"جاری کالز کا نظم کریں"</string>
<string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"اس سے ایپ کو آپ کے آلے پر جاری کالز کے بارے میں تفصیلات دیکھنے اور ان کالز کو کنٹرول کرنے کی اجازت ملتی ہے۔"</string>
+ <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+ <skip />
+ <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+ <skip />
<string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"سیل کے نشریاتی پیغامات پڑھیں"</string>
<string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"ایپ کو آپ کے آلے کو موصولہ سیل کے نشریاتی پیغامات پڑھنے کی اجازت دیتا ہے۔ سیل کی نشریاتی الرٹس آپ کو ایمرجنسی حالات سے مطلع کرنے کیلئے کچھ مقامات میں مہیا کی جاتی ہیں۔ نقصان دہ ایپس کوئی ایمرجنسی سیل کا نشریہ موصول ہونے پر آپ کے آلے کی کارکردگی یا عمل میں خلل ڈال سکتی ہیں۔"</string>
<string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"سبسکرائب کردہ فیڈز پڑھیں"</string>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index 9388b0f..8b52c36 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -370,6 +370,10 @@
<string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Qabul qilingan aholini ogohlantirish xabarlarini shu holicha uzatish uchun ilovani aholini ogohlantirish moduliga bogʻlash imkonini beradi. Ilovaga ayrim mamlakatlarda aholini favqulodda vaziyatlarda ogohlantirish uchun yuboriladigan tarqatma xabarlarni oʻqish uchun ruxsat beradi. Zararli dasturlar bunday xabarlar kelayotgan qurilmaning ishlashiga xalaqit qilishi mumkin."</string>
<string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Amaldagi chaqiruvlarni boshqarish"</string>
<string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Ilovaga qurilmangizdagi amaldagi chaqiruv tafsilotlarini koʻrish va uni boshqarish huquqini beradi."</string>
+ <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+ <skip />
+ <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+ <skip />
<string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"uyali tarmoq operatori xabarlarini o‘qish"</string>
<string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Ilovaga qurilmangiz tomonidan qabul qilingan uyali tarmoq operatori xabarlarini o‘qish uchun ruxsat beradi. Uyali tarmoq operatorining ogohlantiruvchi xabarlari ba’zi manzillarga favqulodda holatlar haqida ogohlantirish uchun jo‘natiladi. Zararli ilovalar uyali tarmoq orqali favqulodda xabar qabul qilinganda qurilmangizning ish faoliyati yoki amallariga xalaqit qilishi mumkin"</string>
<string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"obunalarni o‘qish"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index b9410c1..3149c18 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -370,6 +370,10 @@
<string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Cho phép ứng dụng liên kết với mô-đun truyền phát trên di động để chuyển tiếp tin nhắn truyền phát trên di động ngay khi nhận được. Ở một số vị trí, thông báo truyền phát trên di động sẽ được gửi nhằm cảnh báo cho bạn về các tình huống khẩn cấp. Các ứng dụng độc hại có thể ảnh hưởng đến hiệu suất hoặc hoạt động của thiết bị khi nhận được tin nhắn truyền phát trên di động lúc khẩn cấp."</string>
<string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Quản lý cuộc gọi đang diễn ra"</string>
<string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Cho phép một ứng dụng xem thông tin chi tiết về các cuộc gọi đang diễn ra trên thiết bị và kiểm soát các cuộc gọi này."</string>
+ <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+ <skip />
+ <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+ <skip />
<string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"đọc tin nhắn quảng bá"</string>
<string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Cho phép ứng dụng đọc tin nhắn quảng bá mà thiết bị của bạn nhận được. Tin nhắn quảng bá cảnh báo được gửi ở một số địa điểm nhằm cảnh báo cho bạn về các tình huống khẩn cấp. Các ứng dụng độc hại có thể gây ảnh hưởng đến hiệu suất hoặc hoạt động của thiết bị của bạn khi nhận được tin nhắn quảng bá khẩn cấp."</string>
<string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"đọc nguồn cấp dữ liệu đã đăng ký"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 488dcc6..168a50e 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -370,6 +370,10 @@
<string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"允许应用绑定到小区广播模块,以便及时转发收到的小区广播消息。小区广播消息是在某些地区发送的、用于发布紧急情况警告的提醒信息。恶意应用可能会在您的设备收到紧急小区广播时干扰设备的性能或操作。"</string>
<string name="permlab_manageOngoingCalls" msgid="281244770664231782">"管理正在进行的通话"</string>
<string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"允许应用查看有关设备上正在进行的通话的详细信息并控制这些通话。"</string>
+ <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+ <skip />
+ <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+ <skip />
<string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"读取小区广播消息"</string>
<string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"允许应用读取您的设备收到的小区广播消息。小区广播消息是在某些地区发送的、用于发布紧急情况警告的提醒信息。恶意应用可能会在您收到小区紧急广播时干扰您设备的性能或操作。"</string>
<string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"读取订阅的供稿"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index db117c52..c6c0997 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -370,6 +370,10 @@
<string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"允許應用程式繫結至區域廣播模組,以在收到區域廣播訊息時轉寄訊息。在某些地點,系統會發出區域廣播通知,提示你有緊急狀況發生。惡意應用程式可能會在裝置收到緊急區域廣播時,干擾裝置的效能或運作。"</string>
<string name="permlab_manageOngoingCalls" msgid="281244770664231782">"管理正在進行的通話"</string>
<string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"允許應用程式查看裝置上正在進行的通話詳情並控制通話。"</string>
+ <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+ <skip />
+ <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+ <skip />
<string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"讀取區域廣播訊息"</string>
<string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"允許應用程式讀取你裝置接收的區域廣播訊息。某些地點會發出區域廣播警報,警告你發生緊急狀況。惡意應用程式可能會在裝置收到緊急區域廣播時,干擾裝置的性能或運作。"</string>
<string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"讀取訂閱的資訊提供"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index e91dc76..3aa79c4 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -370,6 +370,10 @@
<string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"允許應用程式繫結至區域廣播模組,以便轉送收到的區域廣播訊息。某些地點會發出區域廣播警示,警告你有緊急狀況發生。請注意,惡意應用程式可能會在裝置收到緊急區域廣播時,干擾裝置的效能或運作。"</string>
<string name="permlab_manageOngoingCalls" msgid="281244770664231782">"管理進行中的通話"</string>
<string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"允許應用程式查看裝置上進行中通話的詳細資料,並控制這些通話。"</string>
+ <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+ <skip />
+ <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+ <skip />
<string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"讀取區域廣播訊息"</string>
<string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"允許應用程式讀取你裝置收到的區域廣播訊息。某些地點會發出區域廣播警示,警告你有緊急狀況發生。請注意,惡意應用程式可能會在裝置收到緊急區域廣播時,干擾裝置的效能或運作。"</string>
<string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"讀取訂閱資訊提供"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 87a25ca..c18b7d4 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -370,6 +370,10 @@
<string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Ivumela uhlelo lokusebenza ukuthi luboshezelwe kumojuli yokusakaza kweselula ukuze kudluliselwe imilayezo yokusakaza yeselula njengoba itholwa. Izexwayiso zokusakaza kweselula zilethwa kwezinye izindawo ukuze zikuxwayise ngezimo zesimo esiphuthumayo. Izinhlelo zokusebenza ezinobungozi zingaphazamisa ngokusebenza noma ukusetshenziswa kwedivayisi yakho uma ukusakaza kweselula kwesimo esiphuthumayo kwamukelwa."</string>
<string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Phatha amakholi aqhubekayo"</string>
<string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Ivumela uhlelo lokusebenza ukubona imininingwane emayelana namakholi aqhubekayo kudivayisi yakho nokulawula lamakholi."</string>
+ <!-- no translation found for permlab_accessLastKnownCellId (7638226620825665130) -->
+ <skip />
+ <!-- no translation found for permdesc_accessLastKnownCellId (6664621339249308857) -->
+ <skip />
<string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"funda imilayezo yokusakaza yeselula"</string>
<string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Ivumela uhlelo lokusebenza ukufunda imilayezo yokusakaza yeselula etholwe idivayisi yakho. Izaziso zokusakaza zeselula zilethwa kwezinye izindawo ukukuxwayisa ngezimo ezisheshayo. Izinhlelo zokusebenza ezingalungile zingaphazamisana nokusebenza noma umsebenzi wedivayisi yakho uma ukusakaza kweselula kwesimo esisheshayo kutholwa."</string>
<string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"funda izifunzo ezikhokhelwayo"</string>
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 35276bf..6884fc0 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -3438,6 +3438,20 @@
<!-- Attributes that can be supplied in an AndroidManifest.xml
<code>data</code> tag, a child of the
{@link #AndroidManifestIntentFilter intent-filter} tag, describing
+ a group matching rule consisting of one or more
+ {@link #AndroidManifestData data} tags that must all match. This
+ tag can be specified multiple times to create multiple groups that
+ will be matched in the order they are defined. -->
+ <declare-styleable name="AndroidManifestUriRelativeFilterGroup"
+ parent="AndroidManifestIntentFilter">
+ <!-- Specify if this group is allow rule or disallow rule. If this
+ attribute is not specified then it is assumed to be true -->
+ <attr name="allow" format="boolean"/>
+ </declare-styleable>
+
+ <!-- Attributes that can be supplied in an AndroidManifest.xml
+ <code>data</code> tag, a child of the
+ {@link #AndroidManifestIntentFilter intent-filter} tag, describing
the types of data that match. This tag can be specified multiple
times to supply multiple data options, as described in the
{@link android.content.IntentFilter} class. Note that all such
@@ -3445,7 +3459,8 @@
<code><data android:scheme="myscheme" android:host="me.com" /></code>
is equivalent to <code><data android:scheme="myscheme" />
<data android:host="me.com" /></code>. -->
- <declare-styleable name="AndroidManifestData" parent="AndroidManifestIntentFilter">
+ <declare-styleable name="AndroidManifestData"
+ parent="AndroidManifestIntentFilter AndroidManifestUriRelativeFilterGroup">
<!-- Specify a MIME type that is handled, as per
{@link android.content.IntentFilter#addDataType
IntentFilter.addDataType()}.
@@ -3549,6 +3564,70 @@
IntentFilter.addDataPath()} with
{@link android.os.PatternMatcher#PATTERN_SUFFIX}. -->
<attr name="pathSuffix" />
+ <!-- Specify a URI query that must exactly match, as a
+ {@link android.content.UriRelativeFilter UriRelativeFilter} with
+ {@link android.os.PatternMatcher#PATTERN_LITERAL}. -->
+ <attr name="query" format="string" />
+ <!-- Specify a URI query that must be a prefix to match, as a
+ {@link android.content.UriRelativeFilter UriRelativeFilter} with
+ {@link android.os.PatternMatcher#PATTERN_PREFIX}. -->
+ <attr name="queryPrefix" format="string" />
+ <!-- Specify a URI query that matches a simple pattern, as a
+ {@link android.content.UriRelativeFilter UriRelativeFilter} with
+ {@link android.os.PatternMatcher#PATTERN_SIMPLE_GLOB}.
+ Note that because '\' is used as an escape character when
+ reading the string from XML (before it is parsed as a pattern),
+ you will need to double-escape: for example a literal "*" would
+ be written as "\\*" and a literal "\" would be written as
+ "\\\\". This is basically the same as what you would need to
+ write if constructing the string in Java code. -->
+ <attr name="queryPattern" format="string" />
+ <!-- Specify a URI query that matches an advanced pattern, as a
+ {@link android.content.UriRelativeFilter UriRelativeFilter} with
+ {@link android.os.PatternMatcher#PATTERN_ADVANCED_GLOB}.
+ Note that because '\' is used as an escape character when
+ reading the string from XML (before it is parsed as a pattern),
+ you will need to double-escape: for example a literal "*" would
+ be written as "\\*" and a literal "\" would be written as
+ "\\\\". This is basically the same as what you would need to
+ write if constructing the string in Java code. -->
+ <attr name="queryAdvancedPattern" format="string" />
+ <!-- Specify a URI query that must be a suffix to match, as a
+ {@link android.content.UriRelativeFilter UriRelativeFilter} with
+ {@link android.os.PatternMatcher#PATTERN_SUFFIX}. -->
+ <attr name="querySuffix" format="string" />
+ <!-- Specify a URI fragment that must exactly match, as a
+ {@link android.content.UriRelativeFilter UriRelativeFilter} with
+ {@link android.os.PatternMatcher#PATTERN_LITERAL}. -->
+ <attr name="fragment" format="string" />
+ <!-- Specify a URI fragment that must be a prefix to match, as a
+ {@link android.content.UriRelativeFilter UriRelativeFilter} with
+ {@link android.os.PatternMatcher#PATTERN_PREFIX}. -->
+ <attr name="fragmentPrefix" format="string" />
+ <!-- Specify a URI fragment that matches a simple pattern, as a
+ {@link android.content.UriRelativeFilter UriRelativeFilter} with
+ {@link android.os.PatternMatcher#PATTERN_SIMPLE_GLOB}.
+ Note that because '\' is used as an escape character when
+ reading the string from XML (before it is parsed as a pattern),
+ you will need to double-escape: for example a literal "*" would
+ be written as "\\*" and a literal "\" would be written as
+ "\\\\". This is basically the same as what you would need to
+ write if constructing the string in Java code. -->
+ <attr name="fragmentPattern" format="string" />
+ <!-- Specify a URI fragment that matches an advanced pattern, as a
+ {@link android.content.UriRelativeFilter UriRelativeFilter} with
+ {@link android.os.PatternMatcher#PATTERN_ADVANCED_GLOB}.
+ Note that because '\' is used as an escape character when
+ reading the string from XML (before it is parsed as a pattern),
+ you will need to double-escape: for example a literal "*" would
+ be written as "\\*" and a literal "\" would be written as
+ "\\\\". This is basically the same as what you would need to
+ write if constructing the string in Java code. -->
+ <attr name="fragmentAdvancedPattern" format="string" />
+ <!-- Specify a URI fragment that must be a suffix to match, as a
+ {@link android.content.UriRelativeFilter UriRelativeFilter} with
+ {@link android.os.PatternMatcher#PATTERN_SUFFIX}. -->
+ <attr name="fragmentSuffix" format="string" />
</declare-styleable>
<!-- Attributes that can be supplied in an AndroidManifest.xml
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 23c78fd..ebb0d34 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -6908,4 +6908,7 @@
<!-- Defines the minimum interval (in ms) between two input-based user-activity poke events. -->
<integer name="config_minMillisBetweenInputUserActivityEvents">100</integer>
+
+ <!-- Name of the starting activity for DisplayCompat host. specific to automotive.-->
+ <string name="config_defaultDisplayCompatHostActivity" translatable="false"></string>
</resources>
diff --git a/core/res/res/values/public-staging.xml b/core/res/res/values/public-staging.xml
index b8fc052..830e99c 100644
--- a/core/res/res/values/public-staging.xml
+++ b/core/res/res/values/public-staging.xml
@@ -123,6 +123,26 @@
<public name="featureFlag"/>
<!-- @FlaggedApi("android.multiuser.enable_system_user_only_for_services_and_providers") -->
<public name="systemUserOnly"/>
+ <!-- @FlaggedApi("android.content.pm.relative_reference_intent_filters") -->
+ <public name="allow"/>
+ <!-- @FlaggedApi("android.content.pm.relative_reference_intent_filters") -->
+ <public name="query"/>
+ <!-- @FlaggedApi("android.content.pm.relative_reference_intent_filters") -->
+ <public name="queryPrefix"/>
+ <!-- @FlaggedApi("android.content.pm.relative_reference_intent_filters") -->
+ <public name="queryPattern"/>
+ <!-- @FlaggedApi("android.content.pm.relative_reference_intent_filters") -->
+ <public name="queryAdvancedPattern"/>
+ <!-- @FlaggedApi("android.content.pm.relative_reference_intent_filters") -->
+ <public name="querySuffix"/>
+ <!-- @FlaggedApi("android.content.pm.relative_reference_intent_filters") -->
+ <public name="fragmentPrefix"/>
+ <!-- @FlaggedApi("android.content.pm.relative_reference_intent_filters") -->
+ <public name="fragmentPattern"/>
+ <!-- @FlaggedApi("android.content.pm.relative_reference_intent_filters") -->
+ <public name="fragmentAdvancedPattern"/>
+ <!-- @FlaggedApi("android.content.pm.relative_reference_intent_filters") -->
+ <public name="fragmentSuffix"/>
</staging-public-group>
<staging-public-group type="id" first-id="0x01bc0000">
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index bd3a5e4..558bae7 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -5307,6 +5307,12 @@
<!-- Content description of the expand button icon in the notification when expanded.-->
<string name="expand_button_content_description_expanded">Collapse</string>
+ <!-- A11y announcement when a view is collapsed. -->
+ <string name="content_description_collapsed">Collapsed</string>
+
+ <!-- A11y announcement when a view is expanded. -->
+ <string name="content_description_expanded">Expanded</string>
+
<!-- Accessibility action description on the expand button. -->
<string name="expand_action_accessibility">toggle expansion</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 3c1a42f..dc2f74b 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3826,6 +3826,9 @@
<java-symbol type="string" name="expand_button_content_description_collapsed" />
<java-symbol type="string" name="expand_button_content_description_expanded" />
+ <java-symbol type="string" name="content_description_collapsed" />
+ <java-symbol type="string" name="content_description_expanded" />
+
<!-- Colon separated list of package names that should be granted Notification Listener access -->
<java-symbol type="string" name="config_defaultListenerAccessPackages" />
diff --git a/core/res/res/xml/sms_short_codes.xml b/core/res/res/xml/sms_short_codes.xml
index 3a2e50a..9bb2499 100644
--- a/core/res/res/xml/sms_short_codes.xml
+++ b/core/res/res/xml/sms_short_codes.xml
@@ -34,7 +34,7 @@
http://smscoin.net/software/engine/WordPress/Paid+SMS-registration/ -->
<!-- Arab Emirates -->
- <shortcode country="ae" pattern="\\d{1,5}" free="1017|1355|3214" />
+ <shortcode country="ae" pattern="\\d{1,5}" free="1017|1355|3214|6253" />
<!-- Albania: 5 digits, known short codes listed -->
<shortcode country="al" pattern="\\d{5}" premium="15191|55[56]00" />
@@ -86,7 +86,7 @@
<shortcode country="cn" premium="1066.*" free="1065.*" />
<!-- Colombia: 1-6 digits (not confirmed) -->
- <shortcode country="co" pattern="\\d{1,6}" free="890350|908160|892255|898002|898880|899960|899948|87739|85517" />
+ <shortcode country="co" pattern="\\d{1,6}" free="890350|908160|892255|898002|898880|899960|899948|87739|85517|491289" />
<!-- Cyprus: 4-6 digits (not confirmed), known premium codes listed, plus EU -->
<shortcode country="cy" pattern="\\d{4,6}" premium="7510" free="116\\d{3}" />
@@ -104,6 +104,12 @@
<!-- Denmark: see http://iprs.webspacecommerce.com/Denmark-Premium-Rate-Numbers -->
<shortcode country="dk" pattern="\\d{4,5}" premium="1\\d{3}" free="116\\d{3}|4665" />
+ <!-- Dominican Republic: 1-6 digits (standard system default, not country specific) -->
+ <shortcode country="do" pattern="\\d{1,6}" free="912892" />
+
+ <!-- Ecuador: 1-6 digits (standard system default, not country specific) -->
+ <shortcode country="ec" pattern="\\d{1,6}" free="466453" />
+
<!-- Estonia: short codes 3-5 digits starting with 1, plus premium 7 digit numbers starting with 90, plus EU.
http://www.tja.ee/public/documents/Elektrooniline_side/Oigusaktid/ENG/Estonian_Numbering_Plan_annex_06_09_2010.mht -->
<shortcode country="ee" pattern="1\\d{2,4}" premium="90\\d{5}|15330|1701[0-3]" free="116\\d{3}|95034" />
@@ -154,8 +160,8 @@
http://www.comreg.ie/_fileupload/publications/ComReg1117.pdf -->
<shortcode country="ie" pattern="\\d{5}" premium="5[3-9]\\d{3}" free="50\\d{3}|116\\d{3}" standard="5[12]\\d{3}" />
- <!-- Israel: 4 digits, known premium codes listed -->
- <shortcode country="il" pattern="\\d{4}" premium="4422|4545" />
+ <!-- Israel: 1-5 digits, known premium codes listed -->
+ <shortcode country="il" pattern="\\d{1,5}" premium="4422|4545" free="37477|6681" />
<!-- Italy: 5 digits (premium=41xxx,42xxx), plus EU:
https://www.itu.int/dms_pub/itu-t/oth/02/02/T020200006B0001PDFE.pdf -->
@@ -193,11 +199,14 @@
<shortcode country="mk" pattern="\\d{1,6}" free="129005|122" />
<!-- Mexico: 4-5 digits (not confirmed), known premium codes listed -->
- <shortcode country="mx" pattern="\\d{4,5}" premium="53035|7766" free="26259|46645|50025|50052|5050|76551|88778|9963|91101|45453" />
+ <shortcode country="mx" pattern="\\d{4,6}" premium="53035|7766" free="26259|46645|50025|50052|5050|76551|88778|9963|91101|45453|550346" />
<!-- Malaysia: 5 digits: http://www.skmm.gov.my/attachment/Consumer_Regulation/Mobile_Content_Services_FAQs.pdf -->
<shortcode country="my" pattern="\\d{5}" premium="32298|33776" free="22099|28288|66668" />
+ <!-- Namibia: 1-5 digits (standard system default, not country specific) -->
+ <shortcode country="na" pattern="\\d{1,5}" free="40005" />
+
<!-- The Netherlands, 4 digits, known premium codes listed, plus EU -->
<shortcode country="nl" pattern="\\d{4}" premium="4466|5040" free="116\\d{3}|2223|6225|2223|1662" />
diff --git a/core/tests/coretests/src/android/os/BundleTest.java b/core/tests/coretests/src/android/os/BundleTest.java
index e7b5dff6..93c2e0e 100644
--- a/core/tests/coretests/src/android/os/BundleTest.java
+++ b/core/tests/coretests/src/android/os/BundleTest.java
@@ -20,6 +20,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
@@ -121,6 +122,14 @@
}
@Test
+ public void testEmpty() throws Exception {
+ assertNotNull(Bundle.EMPTY);
+ assertEquals(0, Bundle.EMPTY.size());
+
+ new Bundle(Bundle.EMPTY);
+ }
+
+ @Test
@IgnoreUnderRavenwood(blockedBy = ParcelFileDescriptor.class)
public void testCreateFromParcel() throws Exception {
boolean withFd;
diff --git a/core/tests/coretests/src/android/os/TestLooperManagerTest.java b/core/tests/coretests/src/android/os/TestLooperManagerTest.java
new file mode 100644
index 0000000..5959444
--- /dev/null
+++ b/core/tests/coretests/src/android/os/TestLooperManagerTest.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import android.platform.test.ravenwood.RavenwoodRule;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+@RunWith(AndroidJUnit4.class)
+public class TestLooperManagerTest {
+ private static final String TAG = "TestLooperManagerTest";
+
+ @Rule
+ public final RavenwoodRule mRavenwood = new RavenwoodRule.Builder()
+ .setProvideMainThread(true)
+ .build();
+
+ @Test
+ public void testMainThread() throws Exception {
+ doTest(Looper.getMainLooper());
+ }
+
+ @Test
+ public void testCustomThread() throws Exception {
+ final HandlerThread thread = new HandlerThread(TAG);
+ thread.start();
+ doTest(thread.getLooper());
+ }
+
+ private void doTest(Looper looper) throws Exception {
+ final TestLooperManager tlm =
+ InstrumentationRegistry.getInstrumentation().acquireLooperManager(looper);
+
+ final Handler handler = new Handler(looper);
+ final CountDownLatch latch = new CountDownLatch(1);
+
+ assertFalse(tlm.hasMessages(handler, null, 42));
+
+ handler.sendEmptyMessage(42);
+ handler.post(() -> {
+ latch.countDown();
+ });
+ assertTrue(tlm.hasMessages(handler, null, 42));
+ assertFalse(latch.await(100, TimeUnit.MILLISECONDS));
+
+ final Message first = tlm.next();
+ assertEquals(42, first.what);
+ assertNull(first.callback);
+ tlm.execute(first);
+ assertFalse(tlm.hasMessages(handler, null, 42));
+ assertFalse(latch.await(100, TimeUnit.MILLISECONDS));
+ tlm.recycle(first);
+
+ final Message second = tlm.next();
+ assertNotNull(second.callback);
+ tlm.execute(second);
+ assertFalse(tlm.hasMessages(handler, null, 42));
+ assertTrue(latch.await(100, TimeUnit.MILLISECONDS));
+ tlm.recycle(second);
+
+ tlm.release();
+ }
+}
diff --git a/core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java b/core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java
index a709d7b..52ff0d4 100644
--- a/core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java
+++ b/core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java
@@ -20,6 +20,7 @@
import static android.window.OnBackInvokedDispatcher.PRIORITY_OVERLAY;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.Mockito.atLeast;
@@ -358,7 +359,7 @@
}
@Test
- public void onDetachFromWindow_cancelCallbackAndIgnoreOnBackInvoked() throws RemoteException {
+ public void onDetachFromWindow_cancelsBackAnimation() throws RemoteException {
mDispatcher.registerOnBackInvokedCallback(PRIORITY_DEFAULT, mCallback1);
OnBackInvokedCallbackInfo callbackInfo = assertSetCallbackInfo();
@@ -368,13 +369,12 @@
waitForIdle();
verify(mCallback1).onBackStarted(any(BackEvent.class));
- // This should trigger mCallback1.onBackCancelled()
+ // This should trigger mCallback1.onBackCancelled() and unset the callback in WM
mDispatcher.detachFromWindow();
- // This should be ignored by mCallback1
- callbackInfo.getCallback().onBackInvoked();
+ OnBackInvokedCallbackInfo callbackInfo1 = assertSetCallbackInfo();
+ assertNull(callbackInfo1);
waitForIdle();
- verify(mCallback1, never()).onBackInvoked();
verify(mCallback1).onBackCancelled();
}
}
diff --git a/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java b/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java
index 75b0d4a..145aa60d 100644
--- a/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java
+++ b/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java
@@ -21,7 +21,6 @@
import static android.provider.Settings.Secure.ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN;
import static android.provider.Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE;
import static android.provider.Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES;
-import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_SHORTCUT_KEY;
import static com.android.internal.accessibility.AccessibilityShortcutController.ACCESSIBILITY_HEARING_AIDS_COMPONENT_NAME;
import static com.android.internal.accessibility.AccessibilityShortcutController.COLOR_INVERSION_COMPONENT_NAME;
@@ -83,6 +82,7 @@
import com.android.internal.R;
import com.android.internal.accessibility.AccessibilityShortcutController.FrameworkObjectProvider;
+import com.android.internal.accessibility.common.ShortcutConstants;
import com.android.internal.util.test.FakeSettingsProvider;
import org.junit.AfterClass;
@@ -726,14 +726,14 @@
private void configureNoShortcutService() throws Exception {
when(mAccessibilityManagerService
- .getAccessibilityShortcutTargets(ACCESSIBILITY_SHORTCUT_KEY))
+ .getAccessibilityShortcutTargets(ShortcutConstants.UserShortcutType.HARDWARE))
.thenReturn(Collections.emptyList());
Settings.Secure.putString(mContentResolver, ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, "");
}
private void configureValidShortcutService() throws Exception {
when(mAccessibilityManagerService
- .getAccessibilityShortcutTargets(ACCESSIBILITY_SHORTCUT_KEY))
+ .getAccessibilityShortcutTargets(ShortcutConstants.UserShortcutType.HARDWARE))
.thenReturn(Collections.singletonList(SERVICE_NAME_STRING));
Settings.Secure.putString(
mContentResolver, ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, SERVICE_NAME_STRING);
@@ -744,7 +744,7 @@
(ComponentName) AccessibilityShortcutController.getFrameworkShortcutFeaturesMap()
.keySet().toArray()[0];
when(mAccessibilityManagerService
- .getAccessibilityShortcutTargets(ACCESSIBILITY_SHORTCUT_KEY))
+ .getAccessibilityShortcutTargets(ShortcutConstants.UserShortcutType.HARDWARE))
.thenReturn(Collections.singletonList(featureComponentName.flattenToString()));
Settings.Secure.putString(mContentResolver, ACCESSIBILITY_SHORTCUT_TARGET_SERVICE,
featureComponentName.flattenToString());
@@ -806,7 +806,7 @@
private void configureDefaultAccessibilityService() throws Exception {
when(mAccessibilityManagerService
- .getAccessibilityShortcutTargets(ACCESSIBILITY_SHORTCUT_KEY))
+ .getAccessibilityShortcutTargets(ShortcutConstants.UserShortcutType.HARDWARE))
.thenReturn(Collections.singletonList(SERVICE_NAME_STRING));
when(mResources.getString(R.string.config_defaultAccessibilityService)).thenReturn(
diff --git a/core/tests/coretests/src/com/android/internal/accessibility/dialog/InvisibleToggleAccessibilityServiceTargetTest.java b/core/tests/coretests/src/com/android/internal/accessibility/dialog/InvisibleToggleAccessibilityServiceTargetTest.java
index 69b6a9b7a..2ea044c 100644
--- a/core/tests/coretests/src/com/android/internal/accessibility/dialog/InvisibleToggleAccessibilityServiceTargetTest.java
+++ b/core/tests/coretests/src/com/android/internal/accessibility/dialog/InvisibleToggleAccessibilityServiceTargetTest.java
@@ -39,6 +39,7 @@
import androidx.test.runner.AndroidJUnit4;
import com.android.internal.accessibility.TestUtils;
+import com.android.internal.accessibility.common.ShortcutConstants;
import com.android.internal.util.test.FakeSettingsProvider;
import com.android.internal.util.test.FakeSettingsProviderRule;
@@ -99,7 +100,7 @@
mSut = new InvisibleToggleAccessibilityServiceTarget(
mContextSpy,
- AccessibilityManager.ACCESSIBILITY_SHORTCUT_KEY, accessibilityServiceInfo);
+ ShortcutConstants.UserShortcutType.HARDWARE, accessibilityServiceInfo);
}
@Test
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 62c9e16..2873428 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -642,5 +642,6 @@
<privapp-permissions package="com.android.devicediagnostics">
<permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
+ <permission name="android.permission.BATTERY_STATS"/>
</privapp-permissions>
</permissions>
diff --git a/data/fonts/font_fallback.xml b/data/fonts/font_fallback.xml
index 02e032b..1bd182f 100644
--- a/data/fonts/font_fallback.xml
+++ b/data/fonts/font_fallback.xml
@@ -730,6 +730,16 @@
postScriptName="NotoSerifCJKjp-Regular">NotoSerifCJK-Regular.ttc
</font>
</family>
+ <family lang="ja">
+ <font weight="400" style="normal">
+ NotoSerifHentaigana-EL.ttf
+ <axis tag="wght" stylevalue="400"/>
+ </font>
+ <font weight="700" style="normal">
+ NotoSerifHentaigana-EL.ttf
+ <axis tag="wght" stylevalue="700"/>
+ </font>
+ </family>
<family lang="ko">
<font weight="400" style="normal" index="1" postScriptName="NotoSansCJKjp-Regular">
NotoSansCJK-Regular.ttc
diff --git a/data/fonts/font_fallback_cjkvf.xml b/data/fonts/font_fallback_cjkvf.xml
index 70474ba..75bc74e 100644
--- a/data/fonts/font_fallback_cjkvf.xml
+++ b/data/fonts/font_fallback_cjkvf.xml
@@ -829,6 +829,16 @@
postScriptName="NotoSerifCJKjp-Regular">NotoSerifCJK-Regular.ttc
</font>
</family>
+ <family lang="ja">
+ <font weight="400" style="normal">
+ NotoSerifHentaigana-EL.ttf
+ <axis tag="wght" stylevalue="400"/>
+ </font>
+ <font weight="700" style="normal">
+ NotoSerifHentaigana-EL.ttf
+ <axis tag="wght" stylevalue="700"/>
+ </font>
+ </family>
<family lang="ko">
<font weight="100" style="normal" index="1" postScriptName="NotoSansCJKjp-Thin">
NotoSansCJK-Regular.ttc
diff --git a/data/fonts/fonts.xml b/data/fonts/fonts.xml
index 9320c14..b23f005 100644
--- a/data/fonts/fonts.xml
+++ b/data/fonts/fonts.xml
@@ -1432,6 +1432,16 @@
postScriptName="NotoSerifCJKjp-Regular">NotoSerifCJK-Regular.ttc
</font>
</family>
+ <family lang="ja">
+ <font weight="400" style="normal">
+ NotoSerifHentaigana-EL.ttf
+ <axis tag="wght" stylevalue="400"/>
+ </font>
+ <font weight="700" style="normal">
+ NotoSerifHentaigana-EL.ttf
+ <axis tag="wght" stylevalue="700"/>
+ </font>
+ </family>
<family lang="ko">
<font weight="400" style="normal" index="1" postScriptName="NotoSansCJKjp-Regular">
NotoSansCJK-Regular.ttc
diff --git a/data/fonts/fonts_cjkvf.xml b/data/fonts/fonts_cjkvf.xml
index 8d91edd..1ab71ae 100644
--- a/data/fonts/fonts_cjkvf.xml
+++ b/data/fonts/fonts_cjkvf.xml
@@ -1531,6 +1531,16 @@
postScriptName="NotoSerifCJKjp-Regular">NotoSerifCJK-Regular.ttc
</font>
</family>
+ <family lang="ja">
+ <font weight="400" style="normal">
+ NotoSerifHentaigana-EL.ttf
+ <axis tag="wght" stylevalue="400"/>
+ </font>
+ <font weight="700" style="normal">
+ NotoSerifHentaigana-EL.ttf
+ <axis tag="wght" stylevalue="700"/>
+ </font>
+ </family>
<family lang="ko">
<font weight="100" style="normal" index="1" postScriptName="NotoSansCJKjp-Thin">
NotoSansCJK-Regular.ttc
diff --git a/keystore/java/android/security/AndroidProtectedConfirmation.java b/keystore/java/android/security/AndroidProtectedConfirmation.java
index dfe485a..268e0a5 100644
--- a/keystore/java/android/security/AndroidProtectedConfirmation.java
+++ b/keystore/java/android/security/AndroidProtectedConfirmation.java
@@ -59,6 +59,10 @@
/**
* Requests keystore call into the confirmationui HAL to display a prompt.
+ * @deprecated Android Protected Confirmation had a low adoption rate among Android device
+ * makers and developers alike. Given the lack of devices supporting the
+ * feature, it is deprecated. Developers can use auth-bound Keystore keys
+ * as a partial replacement.
*
* @param listener the binder to use for callbacks.
* @param promptText the prompt to display.
@@ -68,6 +72,7 @@
* @return one of the {@code CONFIRMATIONUI_*} constants, for
* example {@code KeyStore.CONFIRMATIONUI_OK}.
*/
+ @Deprecated
public int presentConfirmationPrompt(IConfirmationCallback listener, String promptText,
byte[] extraData, String locale, int uiOptionsAsFlags) {
try {
@@ -84,11 +89,16 @@
/**
* Requests keystore call into the confirmationui HAL to cancel displaying a prompt.
+ * @deprecated Android Protected Confirmation had a low adoption rate among Android device
+ * makers and developers alike. Given the lack of devices supporting the
+ * feature, it is deprecated. Developers can use auth-bound Keystore keys
+ * as a partial replacement.
*
* @param listener the binder passed to the {@link #presentConfirmationPrompt} method.
* @return one of the {@code CONFIRMATIONUI_*} constants, for
* example {@code KeyStore.CONFIRMATIONUI_OK}.
*/
+ @Deprecated
public int cancelConfirmationPrompt(IConfirmationCallback listener) {
try {
getService().cancelPrompt(listener);
@@ -103,9 +113,14 @@
/**
* Requests keystore to check if the confirmationui HAL is available.
+ * @deprecated Android Protected Confirmation had a low adoption rate among Android device
+ * makers and developers alike. Given the lack of devices supporting the
+ * feature, it is deprecated. Developers can use auth-bound Keystore keys
+ * as a partial replacement.
*
* @return whether the confirmationUI HAL is available.
*/
+ @Deprecated
public boolean isConfirmationPromptSupported() {
try {
return getService().isSupported();
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
index 9c05a3a..83ddfc5 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
@@ -109,13 +109,29 @@
}
}
+ // For curve 25519, KeyMint uses the KM_ALGORITHM_EC constant, but in the Java layer we need
+ // to distinguish between Curve 25519 and other EC algorithms, so we use a different constant
+ // with a value that is outside the range of the enum used for KeyMint algorithms.
+ private static final int ALGORITHM_XDH = KeymasterDefs.KM_ALGORITHM_EC + 1200;
+ private static final int ALGORITHM_ED25519 = ALGORITHM_XDH + 1;
+
/**
- * XDH represents Curve 25519 providers.
+ * XDH represents Curve 25519 agreement key provider.
*/
public static class XDH extends AndroidKeyStoreKeyPairGeneratorSpi {
// XDH is treated as EC.
public XDH() {
- super(KeymasterDefs.KM_ALGORITHM_EC);
+ super(ALGORITHM_XDH);
+ }
+ }
+
+ /**
+ * ED25519 represents Curve 25519 signing key provider.
+ */
+ public static class ED25519 extends AndroidKeyStoreKeyPairGeneratorSpi {
+ // ED25519 is treated as EC.
+ public ED25519() {
+ super(ALGORITHM_ED25519);
}
}
@@ -241,7 +257,9 @@
KeyGenParameterSpec spec;
boolean encryptionAtRestRequired = false;
- int keymasterAlgorithm = mOriginalKeymasterAlgorithm;
+ int keymasterAlgorithm = (mOriginalKeymasterAlgorithm == ALGORITHM_XDH
+ || mOriginalKeymasterAlgorithm == ALGORITHM_ED25519)
+ ? KeymasterDefs.KM_ALGORITHM_EC : mOriginalKeymasterAlgorithm;
if (params instanceof KeyGenParameterSpec) {
spec = (KeyGenParameterSpec) params;
} else if (params instanceof KeyPairGeneratorSpec) {
@@ -610,6 +628,15 @@
if (algSpecificSpec instanceof ECGenParameterSpec) {
ECGenParameterSpec ecSpec = (ECGenParameterSpec) algSpecificSpec;
mEcCurveName = ecSpec.getName();
+ if (mOriginalKeymasterAlgorithm == ALGORITHM_XDH
+ && !mEcCurveName.equalsIgnoreCase("x25519")) {
+ throw new InvalidAlgorithmParameterException("XDH algorithm only supports"
+ + " x25519 curve.");
+ } else if (mOriginalKeymasterAlgorithm == ALGORITHM_ED25519
+ && !mEcCurveName.equalsIgnoreCase("ed25519")) {
+ throw new InvalidAlgorithmParameterException("Ed25519 algorithm only"
+ + " supports ed25519 curve.");
+ }
final Integer ecSpecKeySizeBits = SUPPORTED_EC_CURVE_NAME_TO_SIZE.get(
mEcCurveName.toLowerCase(Locale.US));
if (ecSpecKeySizeBits == null) {
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java b/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java
index 11278e8..d204f13 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java
@@ -86,11 +86,14 @@
put("KeyPairGenerator.EC", PACKAGE_NAME + ".AndroidKeyStoreKeyPairGeneratorSpi$EC");
put("KeyPairGenerator.RSA", PACKAGE_NAME + ".AndroidKeyStoreKeyPairGeneratorSpi$RSA");
put("KeyPairGenerator.XDH", PACKAGE_NAME + ".AndroidKeyStoreKeyPairGeneratorSpi$XDH");
+ put("KeyPairGenerator.ED25519", PACKAGE_NAME
+ + ".AndroidKeyStoreKeyPairGeneratorSpi$ED25519");
// java.security.KeyFactory
putKeyFactoryImpl("EC");
putKeyFactoryImpl("RSA");
putKeyFactoryImpl("XDH");
+ putKeyFactoryImpl("ED25519");
// javax.crypto.KeyGenerator
put("KeyGenerator.AES", PACKAGE_NAME + ".AndroidKeyStoreKeyGeneratorSpi$AES");
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/WindowLayoutComponentImpl.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/WindowLayoutComponentImpl.java
index 9b84a48..6e704f3 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/WindowLayoutComponentImpl.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/WindowLayoutComponentImpl.java
@@ -356,7 +356,7 @@
}
if (featureRect.left == 0
&& featureRect.width() != windowConfiguration.getBounds().width()) {
- Log.wtf(TAG, "Horizontal FoldingFeature must have full width."
+ Log.w(TAG, "Horizontal FoldingFeature must have full width."
+ " BaseFeatureRect: " + baseFeature.getRect()
+ ", FeatureRect: " + featureRect
+ ", WindowConfiguration: " + windowConfiguration);
@@ -364,7 +364,7 @@
}
if (featureRect.top == 0
&& featureRect.height() != windowConfiguration.getBounds().height()) {
- Log.wtf(TAG, "Vertical FoldingFeature must have full height."
+ Log.w(TAG, "Vertical FoldingFeature must have full height."
+ " BaseFeatureRect: " + baseFeature.getRect()
+ ", FeatureRect: " + featureRect
+ ", WindowConfiguration: " + windowConfiguration);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipMenuController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipMenuController.java
similarity index 88%
rename from libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipMenuController.java
rename to libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipMenuController.java
index 0775f52..2f1189a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipMenuController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipMenuController.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * Copyright (C) 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.wm.shell.pip;
+package com.android.wm.shell.common.pip;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
import static android.view.WindowManager.LayoutParams.FLAG_SLIPPERY;
@@ -33,12 +33,13 @@
import android.view.WindowManager;
import com.android.wm.shell.R;
+import com.android.wm.shell.ShellTaskOrganizer;
import java.util.List;
/**
- * Interface to allow {@link com.android.wm.shell.pip.PipTaskOrganizer} to call into
- * PiP menu when certain events happen (task appear/vanish, PiP move, etc.)
+ * Interface to interact with PiP menu when certain events happen
+ * (task appear/vanish, PiP move, etc.).
*/
public interface PipMenuController {
@@ -52,15 +53,15 @@
float ALPHA_NO_CHANGE = -1f;
/**
- * Called when
- * {@link PipTaskOrganizer#onTaskAppeared(RunningTaskInfo, SurfaceControl)}
+ * Called when out implementation of
+ * {@link ShellTaskOrganizer.TaskListener#onTaskAppeared(RunningTaskInfo, SurfaceControl)}
* is called.
*/
void attach(SurfaceControl leash);
/**
- * Called when
- * {@link PipTaskOrganizer#onTaskVanished(RunningTaskInfo)} is called.
+ * Called when our implementation of
+ * {@link ShellTaskOrganizer.TaskListener#onTaskVanished(RunningTaskInfo)} is called.
*/
void detach();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java
index 7b98fa6..8eecf1c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java
@@ -18,18 +18,23 @@
import android.annotation.NonNull;
import android.content.Context;
+import android.os.Handler;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayInsetsController;
import com.android.wm.shell.common.ShellExecutor;
+import com.android.wm.shell.common.SystemWindows;
import com.android.wm.shell.common.annotations.ShellMainThread;
import com.android.wm.shell.common.pip.PipBoundsAlgorithm;
import com.android.wm.shell.common.pip.PipBoundsState;
import com.android.wm.shell.common.pip.PipDisplayLayoutState;
+import com.android.wm.shell.common.pip.PipMediaController;
+import com.android.wm.shell.common.pip.PipUiEventLogger;
import com.android.wm.shell.common.pip.PipUtils;
import com.android.wm.shell.dagger.WMShellBaseModule;
import com.android.wm.shell.dagger.WMSingleton;
+import com.android.wm.shell.pip2.phone.PhonePipMenuController;
import com.android.wm.shell.pip2.phone.PipController;
import com.android.wm.shell.pip2.phone.PipScheduler;
import com.android.wm.shell.pip2.phone.PipTransition;
@@ -86,4 +91,16 @@
@ShellMainThread ShellExecutor mainExecutor) {
return new PipScheduler(context, pipBoundsState, mainExecutor);
}
+
+ @WMSingleton
+ @Provides
+ static PhonePipMenuController providePipPhoneMenuController(Context context,
+ PipBoundsState pipBoundsState, PipMediaController pipMediaController,
+ SystemWindows systemWindows,
+ PipUiEventLogger pipUiEventLogger,
+ @ShellMainThread ShellExecutor mainExecutor,
+ @ShellMainThread Handler mainHandler) {
+ return new PhonePipMenuController(context, pipBoundsState, pipMediaController,
+ systemWindows, pipUiEventLogger, mainExecutor, mainHandler);
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java
index da1ca8d..6250fc5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java
@@ -17,6 +17,8 @@
package com.android.wm.shell.desktopmode;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
+import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static com.android.wm.shell.desktopmode.EnterDesktopTaskTransitionHandler.FINAL_FREEFORM_SCALE;
@@ -86,7 +88,6 @@
mTaskSurface = taskSurface;
mRootTdaOrganizer = taskDisplayAreaOrganizer;
mCurrentType = IndicatorType.NO_INDICATOR;
- createView();
}
/**
@@ -127,34 +128,15 @@
mView = new View(mContext);
final SurfaceControl.Builder builder = new SurfaceControl.Builder();
mRootTdaOrganizer.attachToDisplayArea(mTaskInfo.displayId, builder);
- String description;
- switch (mCurrentType) {
- case TO_DESKTOP_INDICATOR:
- description = "Desktop indicator";
- break;
- case TO_FULLSCREEN_INDICATOR:
- description = "Fullscreen indicator";
- break;
- case TO_SPLIT_LEFT_INDICATOR:
- description = "Split Left indicator";
- break;
- case TO_SPLIT_RIGHT_INDICATOR:
- description = "Split Right indicator";
- break;
- default:
- description = "Invalid indicator";
- break;
- }
mLeash = builder
- .setName(description)
+ .setName("Desktop Mode Visual Indicator")
.setContainerLayer()
.build();
t.show(mLeash);
final WindowManager.LayoutParams lp =
- new WindowManager.LayoutParams(screenWidth, screenHeight,
- WindowManager.LayoutParams.TYPE_APPLICATION,
- WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, PixelFormat.TRANSPARENT);
- lp.setTitle(description + " for Task=" + mTaskInfo.taskId);
+ new WindowManager.LayoutParams(screenWidth, screenHeight, TYPE_APPLICATION,
+ FLAG_NOT_FOCUSABLE, PixelFormat.TRANSPARENT);
+ lp.setTitle("Desktop Mode Visual Indicator");
lp.setTrustedOverlay();
final WindowlessWindowManager windowManager = new WindowlessWindowManager(
mTaskInfo.configuration, mLeash,
@@ -201,6 +183,9 @@
*/
private void transitionIndicator(IndicatorType newType) {
if (mCurrentType == newType) return;
+ if (mView == null) {
+ createView();
+ }
if (mCurrentType == IndicatorType.NO_INDICATOR) {
fadeInIndicator(newType);
} else if (newType == IndicatorType.NO_INDICATOR) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
index 4f5c39a..28c06a4 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
@@ -919,22 +919,27 @@
}
if (taskBounds.top <= transitionAreaHeight) {
moveToFullscreenWithAnimation(taskInfo, position)
+ return
}
if (inputCoordinate.x <= transitionAreaWidth) {
releaseVisualIndicator()
- var wct = WindowContainerTransaction()
+ val wct = WindowContainerTransaction()
addMoveToSplitChanges(wct, taskInfo)
splitScreenController.requestEnterSplitSelect(taskInfo, wct,
SPLIT_POSITION_TOP_OR_LEFT, taskBounds)
+ return
}
if (inputCoordinate.x >= (displayController.getDisplayLayout(taskInfo.displayId)?.width()
?.minus(transitionAreaWidth) ?: return)) {
releaseVisualIndicator()
- var wct = WindowContainerTransaction()
+ val wct = WindowContainerTransaction()
addMoveToSplitChanges(wct, taskInfo)
splitScreenController.requestEnterSplitSelect(taskInfo, wct,
SPLIT_POSITION_BOTTOM_OR_RIGHT, taskBounds)
+ return
}
+ // A freeform drag-move ended, remove the indicator immediately.
+ releaseVisualIndicator()
}
/**
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 07b8f11..52a06e0 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
@@ -86,6 +86,7 @@
import com.android.wm.shell.common.pip.PipBoundsAlgorithm;
import com.android.wm.shell.common.pip.PipBoundsState;
import com.android.wm.shell.common.pip.PipDisplayLayoutState;
+import com.android.wm.shell.common.pip.PipMenuController;
import com.android.wm.shell.common.pip.PipUiEventLogger;
import com.android.wm.shell.common.pip.PipUtils;
import com.android.wm.shell.pip.phone.PipMotionHelper;
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 8e375a9..e739266 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
@@ -68,6 +68,7 @@
import com.android.wm.shell.common.pip.PipBoundsAlgorithm;
import com.android.wm.shell.common.pip.PipBoundsState;
import com.android.wm.shell.common.pip.PipDisplayLayoutState;
+import com.android.wm.shell.common.pip.PipMenuController;
import com.android.wm.shell.common.pip.PipUtils;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.splitscreen.SplitScreenController;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java
index 0e70736..d1fd207 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java
@@ -40,6 +40,7 @@
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.pip.PipBoundsAlgorithm;
import com.android.wm.shell.common.pip.PipBoundsState;
+import com.android.wm.shell.common.pip.PipMenuController;
import com.android.wm.shell.common.split.SplitScreenUtils;
import com.android.wm.shell.sysui.ShellInit;
import com.android.wm.shell.transition.Transitions;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java
index 7606526..d8e8b58 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java
@@ -41,8 +41,8 @@
import com.android.wm.shell.common.pip.PipBoundsState;
import com.android.wm.shell.common.pip.PipMediaController;
import com.android.wm.shell.common.pip.PipMediaController.ActionListener;
+import com.android.wm.shell.common.pip.PipMenuController;
import com.android.wm.shell.common.pip.PipUiEventLogger;
-import com.android.wm.shell.pip.PipMenuController;
import com.android.wm.shell.pip.PipSurfaceTransactionHelper;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.splitscreen.SplitScreenController;
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 c6803f7..843c84a 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
@@ -40,7 +40,7 @@
import com.android.internal.protolog.common.ProtoLog;
import com.android.wm.shell.R;
import com.android.wm.shell.common.SystemWindows;
-import com.android.wm.shell.pip.PipMenuController;
+import com.android.wm.shell.common.pip.PipMenuController;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
import java.util.List;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipTaskOrganizer.java
index 21223c9a..cac63eb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipTaskOrganizer.java
@@ -28,10 +28,10 @@
import com.android.wm.shell.common.pip.PipBoundsAlgorithm;
import com.android.wm.shell.common.pip.PipBoundsState;
import com.android.wm.shell.common.pip.PipDisplayLayoutState;
+import com.android.wm.shell.common.pip.PipMenuController;
import com.android.wm.shell.common.pip.PipUiEventLogger;
import com.android.wm.shell.common.pip.PipUtils;
import com.android.wm.shell.pip.PipAnimationController;
-import com.android.wm.shell.pip.PipMenuController;
import com.android.wm.shell.pip.PipParamsChangedForwarder;
import com.android.wm.shell.pip.PipSurfaceTransactionHelper;
import com.android.wm.shell.pip.PipTaskOrganizer;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipTransition.java
index 571c839..d16a692 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipTransition.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipTransition.java
@@ -25,10 +25,10 @@
import static android.view.WindowManager.TRANSIT_TO_BACK;
import static android.view.WindowManager.transitTypeToString;
+import static com.android.wm.shell.common.pip.PipMenuController.ALPHA_NO_CHANGE;
import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_LEAVE_PIP;
import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_REMOVE_STACK;
import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_TO_PIP;
-import static com.android.wm.shell.pip.PipMenuController.ALPHA_NO_CHANGE;
import static com.android.wm.shell.pip.PipTransitionState.ENTERED_PIP;
import static com.android.wm.shell.pip.PipTransitionState.ENTERING_PIP;
import static com.android.wm.shell.pip.PipTransitionState.EXITING_PIP;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/PipSurfaceTransactionHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/PipSurfaceTransactionHelper.java
new file mode 100644
index 0000000..24077a3
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/PipSurfaceTransactionHelper.java
@@ -0,0 +1,277 @@
+/*
+ * 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.pip2;
+
+import android.content.Context;
+import android.graphics.Matrix;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.view.Choreographer;
+import android.view.SurfaceControl;
+
+import com.android.wm.shell.R;
+import com.android.wm.shell.transition.Transitions;
+
+/**
+ * Abstracts the common operations on {@link SurfaceControl.Transaction} for PiP transition.
+ */
+public class PipSurfaceTransactionHelper {
+ /** for {@link #scale(SurfaceControl.Transaction, SurfaceControl, Rect, Rect)} operation */
+ private final Matrix mTmpTransform = new Matrix();
+ private final float[] mTmpFloat9 = new float[9];
+ private final RectF mTmpSourceRectF = new RectF();
+ private final RectF mTmpDestinationRectF = new RectF();
+ private final Rect mTmpDestinationRect = new Rect();
+
+ private int mCornerRadius;
+ private int mShadowRadius;
+
+ public PipSurfaceTransactionHelper(Context context) {
+ onDensityOrFontScaleChanged(context);
+ }
+
+ /**
+ * Called when display size or font size of settings changed
+ *
+ * @param context the current context
+ */
+ public void onDensityOrFontScaleChanged(Context context) {
+ mCornerRadius = context.getResources().getDimensionPixelSize(R.dimen.pip_corner_radius);
+ mShadowRadius = context.getResources().getDimensionPixelSize(R.dimen.pip_shadow_radius);
+ }
+
+ /**
+ * Operates the alpha on a given transaction and leash
+ * @return same {@link PipSurfaceTransactionHelper} instance for method chaining
+ */
+ public PipSurfaceTransactionHelper alpha(SurfaceControl.Transaction tx, SurfaceControl leash,
+ float alpha) {
+ tx.setAlpha(leash, alpha);
+ return this;
+ }
+
+ /**
+ * Operates the crop (and position) on a given transaction and leash
+ * @return same {@link PipSurfaceTransactionHelper} instance for method chaining
+ */
+ public PipSurfaceTransactionHelper crop(SurfaceControl.Transaction tx, SurfaceControl leash,
+ Rect destinationBounds) {
+ tx.setWindowCrop(leash, destinationBounds.width(), destinationBounds.height())
+ .setPosition(leash, destinationBounds.left, destinationBounds.top);
+ return this;
+ }
+
+ /**
+ * Operates the scale (setMatrix) on a given transaction and leash
+ * @return same {@link PipSurfaceTransactionHelper} instance for method chaining
+ */
+ public PipSurfaceTransactionHelper scale(SurfaceControl.Transaction tx, SurfaceControl leash,
+ Rect sourceBounds, Rect destinationBounds) {
+ mTmpDestinationRectF.set(destinationBounds);
+ return scale(tx, leash, sourceBounds, mTmpDestinationRectF, 0 /* degrees */);
+ }
+
+ /**
+ * Operates the scale (setMatrix) on a given transaction and leash
+ * @return same {@link PipSurfaceTransactionHelper} instance for method chaining
+ */
+ public PipSurfaceTransactionHelper scale(SurfaceControl.Transaction tx, SurfaceControl leash,
+ Rect sourceBounds, RectF destinationBounds) {
+ return scale(tx, leash, sourceBounds, destinationBounds, 0 /* degrees */);
+ }
+
+ /**
+ * Operates the scale (setMatrix) on a given transaction and leash
+ * @return same {@link PipSurfaceTransactionHelper} instance for method chaining
+ */
+ public PipSurfaceTransactionHelper scale(SurfaceControl.Transaction tx, SurfaceControl leash,
+ Rect sourceBounds, Rect destinationBounds, float degrees) {
+ mTmpDestinationRectF.set(destinationBounds);
+ return scale(tx, leash, sourceBounds, mTmpDestinationRectF, degrees);
+ }
+
+ /**
+ * Operates the scale (setMatrix) on a given transaction and leash, along with a rotation.
+ * @return same {@link PipSurfaceTransactionHelper} instance for method chaining
+ */
+ public PipSurfaceTransactionHelper scale(SurfaceControl.Transaction tx, SurfaceControl leash,
+ Rect sourceBounds, RectF destinationBounds, float degrees) {
+ mTmpSourceRectF.set(sourceBounds);
+ // We want the matrix to position the surface relative to the screen coordinates so offset
+ // the source to 0,0
+ mTmpSourceRectF.offsetTo(0, 0);
+ mTmpDestinationRectF.set(destinationBounds);
+ mTmpTransform.setRectToRect(mTmpSourceRectF, mTmpDestinationRectF, Matrix.ScaleToFit.FILL);
+ mTmpTransform.postRotate(degrees,
+ mTmpDestinationRectF.centerX(), mTmpDestinationRectF.centerY());
+ tx.setMatrix(leash, mTmpTransform, mTmpFloat9);
+ return this;
+ }
+
+ /**
+ * Operates the scale (setMatrix) on a given transaction and leash
+ * @return same {@link PipSurfaceTransactionHelper} instance for method chaining
+ */
+ public PipSurfaceTransactionHelper scaleAndCrop(SurfaceControl.Transaction tx,
+ SurfaceControl leash, Rect sourceRectHint,
+ Rect sourceBounds, Rect destinationBounds, Rect insets,
+ boolean isInPipDirection, float fraction) {
+ mTmpDestinationRect.set(sourceBounds);
+ // Similar to {@link #scale}, we want to position the surface relative to the screen
+ // coordinates so offset the bounds to 0,0
+ mTmpDestinationRect.offsetTo(0, 0);
+ mTmpDestinationRect.inset(insets);
+ // Scale to the bounds no smaller than the destination and offset such that the top/left
+ // of the scaled inset source rect aligns with the top/left of the destination bounds
+ final float scale;
+ if (isInPipDirection
+ && sourceRectHint != null && sourceRectHint.width() < sourceBounds.width()) {
+ // scale by sourceRectHint if it's not edge-to-edge, for entering PiP transition only.
+ final float endScale = sourceBounds.width() <= sourceBounds.height()
+ ? (float) destinationBounds.width() / sourceRectHint.width()
+ : (float) destinationBounds.height() / sourceRectHint.height();
+ final float startScale = sourceBounds.width() <= sourceBounds.height()
+ ? (float) destinationBounds.width() / sourceBounds.width()
+ : (float) destinationBounds.height() / sourceBounds.height();
+ scale = (1 - fraction) * startScale + fraction * endScale;
+ } else {
+ scale = Math.max((float) destinationBounds.width() / sourceBounds.width(),
+ (float) destinationBounds.height() / sourceBounds.height());
+ }
+ final float left = destinationBounds.left - insets.left * scale;
+ final float top = destinationBounds.top - insets.top * scale;
+ mTmpTransform.setScale(scale, scale);
+ tx.setMatrix(leash, mTmpTransform, mTmpFloat9)
+ .setCrop(leash, mTmpDestinationRect)
+ .setPosition(leash, left, top);
+ return this;
+ }
+
+ /**
+ * Operates the rotation according to the given degrees and scale (setMatrix) according to the
+ * source bounds and rotated destination bounds. The crop will be the unscaled source bounds.
+ * @return same {@link PipSurfaceTransactionHelper} instance for method chaining
+ */
+ public PipSurfaceTransactionHelper rotateAndScaleWithCrop(SurfaceControl.Transaction tx,
+ SurfaceControl leash, Rect sourceBounds, Rect destinationBounds, Rect insets,
+ float degrees, float positionX, float positionY, boolean isExpanding,
+ boolean clockwise) {
+ mTmpDestinationRect.set(sourceBounds);
+ mTmpDestinationRect.inset(insets);
+ final int srcW = mTmpDestinationRect.width();
+ final int srcH = mTmpDestinationRect.height();
+ final int destW = destinationBounds.width();
+ final int destH = destinationBounds.height();
+ // Scale by the short side so there won't be empty area if the aspect ratio of source and
+ // destination are different.
+ final float scale = srcW <= srcH ? (float) destW / srcW : (float) destH / srcH;
+ final Rect crop = mTmpDestinationRect;
+ crop.set(0, 0, Transitions.SHELL_TRANSITIONS_ROTATION ? destH
+ : destW, Transitions.SHELL_TRANSITIONS_ROTATION ? destW : destH);
+ // Inverse scale for crop to fit in screen coordinates.
+ crop.scale(1 / scale);
+ crop.offset(insets.left, insets.top);
+ if (isExpanding) {
+ // Expand bounds (shrink insets) in source orientation.
+ positionX -= insets.left * scale;
+ positionY -= insets.top * scale;
+ } else {
+ // Shrink bounds (expand insets) in destination orientation.
+ if (clockwise) {
+ positionX -= insets.top * scale;
+ positionY += insets.left * scale;
+ } else {
+ positionX += insets.top * scale;
+ positionY -= insets.left * scale;
+ }
+ }
+ mTmpTransform.setScale(scale, scale);
+ mTmpTransform.postRotate(degrees);
+ mTmpTransform.postTranslate(positionX, positionY);
+ tx.setMatrix(leash, mTmpTransform, mTmpFloat9).setCrop(leash, crop);
+ return this;
+ }
+
+ /**
+ * Resets the scale (setMatrix) on a given transaction and leash if there's any
+ *
+ * @return same {@link PipSurfaceTransactionHelper} instance for method chaining
+ */
+ public PipSurfaceTransactionHelper resetScale(SurfaceControl.Transaction tx,
+ SurfaceControl leash,
+ Rect destinationBounds) {
+ tx.setMatrix(leash, Matrix.IDENTITY_MATRIX, mTmpFloat9)
+ .setPosition(leash, destinationBounds.left, destinationBounds.top);
+ return this;
+ }
+
+ /**
+ * Operates the round corner radius on a given transaction and leash
+ * @return same {@link PipSurfaceTransactionHelper} instance for method chaining
+ */
+ public PipSurfaceTransactionHelper round(SurfaceControl.Transaction tx, SurfaceControl leash,
+ boolean applyCornerRadius) {
+ tx.setCornerRadius(leash, applyCornerRadius ? mCornerRadius : 0);
+ return this;
+ }
+
+ /**
+ * Operates the round corner radius on a given transaction and leash, scaled by bounds
+ * @return same {@link PipSurfaceTransactionHelper} instance for method chaining
+ */
+ public PipSurfaceTransactionHelper round(SurfaceControl.Transaction tx, SurfaceControl leash,
+ Rect fromBounds, Rect toBounds) {
+ final float scale = (float) (Math.hypot(fromBounds.width(), fromBounds.height())
+ / Math.hypot(toBounds.width(), toBounds.height()));
+ tx.setCornerRadius(leash, mCornerRadius * scale);
+ return this;
+ }
+
+ /**
+ * Operates the shadow radius on a given transaction and leash
+ * @return same {@link PipSurfaceTransactionHelper} instance for method chaining
+ */
+ public PipSurfaceTransactionHelper shadow(SurfaceControl.Transaction tx, SurfaceControl leash,
+ boolean applyShadowRadius) {
+ tx.setShadowRadius(leash, applyShadowRadius ? mShadowRadius : 0);
+ return this;
+ }
+
+ /**
+ * Interface to standardize {@link SurfaceControl.Transaction} generation across PiP.
+ */
+ public interface SurfaceControlTransactionFactory {
+ /**
+ * @return a new transaction to operate on.
+ */
+ SurfaceControl.Transaction getTransaction();
+ }
+
+ /**
+ * Implementation of {@link SurfaceControlTransactionFactory} that returns
+ * {@link SurfaceControl.Transaction} with VsyncId being set.
+ */
+ public static class VsyncSurfaceControlTransactionFactory
+ implements SurfaceControlTransactionFactory {
+ @Override
+ public SurfaceControl.Transaction getTransaction() {
+ final SurfaceControl.Transaction tx = new SurfaceControl.Transaction();
+ tx.setFrameTimelineVsync(Choreographer.getInstance().getVsyncId());
+ return tx;
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PhonePipMenuController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PhonePipMenuController.java
new file mode 100644
index 0000000..2478252
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PhonePipMenuController.java
@@ -0,0 +1,608 @@
+/*
+ * 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.pip2.phone;
+
+import static android.view.WindowManager.SHELL_ROOT_LAYER_PIP;
+
+import android.annotation.Nullable;
+import android.app.ActivityManager;
+import android.app.RemoteAction;
+import android.content.Context;
+import android.graphics.Matrix;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.os.Debug;
+import android.os.Handler;
+import android.os.RemoteException;
+import android.util.Size;
+import android.view.MotionEvent;
+import android.view.SurfaceControl;
+import android.view.View;
+import android.view.ViewRootImpl;
+import android.view.WindowManagerGlobal;
+
+import com.android.internal.protolog.common.ProtoLog;
+import com.android.wm.shell.common.ShellExecutor;
+import com.android.wm.shell.common.SystemWindows;
+import com.android.wm.shell.common.pip.PipBoundsState;
+import com.android.wm.shell.common.pip.PipMediaController;
+import com.android.wm.shell.common.pip.PipMediaController.ActionListener;
+import com.android.wm.shell.common.pip.PipMenuController;
+import com.android.wm.shell.common.pip.PipUiEventLogger;
+import com.android.wm.shell.pip2.PipSurfaceTransactionHelper;
+import com.android.wm.shell.protolog.ShellProtoLogGroup;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Manages the PiP menu view which can show menu options or a scrim.
+ *
+ * The current media session provides actions whenever there are no valid actions provided by the
+ * current PiP activity. Otherwise, those actions always take precedence.
+ */
+public class PhonePipMenuController implements PipMenuController {
+
+ private static final String TAG = "PhonePipMenuController";
+ private static final boolean DEBUG = false;
+
+ public static final int MENU_STATE_NONE = 0;
+ public static final int MENU_STATE_FULL = 1;
+
+ /**
+ * A listener interface to receive notification on changes in PIP.
+ */
+ public interface Listener {
+ /**
+ * Called when the PIP menu visibility change has started.
+ *
+ * @param menuState the new, about-to-change state of the menu
+ * @param resize whether or not to resize the PiP with the state change
+ */
+ void onPipMenuStateChangeStart(int menuState, boolean resize, Runnable callback);
+
+ /**
+ * Called when the PIP menu state has finished changing/animating.
+ *
+ * @param menuState the new state of the menu.
+ */
+ void onPipMenuStateChangeFinish(int menuState);
+
+ /**
+ * Called when the PIP requested to be expanded.
+ */
+ void onPipExpand();
+
+ /**
+ * Called when the PIP requested to be dismissed.
+ */
+ void onPipDismiss();
+
+ /**
+ * Called when the PIP requested to show the menu.
+ */
+ void onPipShowMenu();
+
+ /**
+ * Called when the PIP requested to enter Split.
+ */
+ void onEnterSplit();
+ }
+
+ private final Matrix mMoveTransform = new Matrix();
+ private final Rect mTmpSourceBounds = new Rect();
+ private final RectF mTmpSourceRectF = new RectF();
+ private final RectF mTmpDestinationRectF = new RectF();
+ private final Context mContext;
+ private final PipBoundsState mPipBoundsState;
+ private final PipMediaController mMediaController;
+ private final ShellExecutor mMainExecutor;
+ private final Handler mMainHandler;
+
+ private final PipSurfaceTransactionHelper.SurfaceControlTransactionFactory
+ mSurfaceControlTransactionFactory;
+ private final float[] mTmpTransform = new float[9];
+
+ private final ArrayList<Listener> mListeners = new ArrayList<>();
+ private final SystemWindows mSystemWindows;
+ private final PipUiEventLogger mPipUiEventLogger;
+
+ private List<RemoteAction> mAppActions;
+ private RemoteAction mCloseAction;
+ private List<RemoteAction> mMediaActions;
+
+ private int mMenuState;
+
+ private PipMenuView mPipMenuView;
+
+ private SurfaceControl mLeash;
+
+ private ActionListener mMediaActionListener = new ActionListener() {
+ @Override
+ public void onMediaActionsChanged(List<RemoteAction> mediaActions) {
+ mMediaActions = new ArrayList<>(mediaActions);
+ updateMenuActions();
+ }
+ };
+
+ public PhonePipMenuController(Context context, PipBoundsState pipBoundsState,
+ PipMediaController mediaController, SystemWindows systemWindows,
+ PipUiEventLogger pipUiEventLogger,
+ ShellExecutor mainExecutor, Handler mainHandler) {
+ mContext = context;
+ mPipBoundsState = pipBoundsState;
+ mMediaController = mediaController;
+ mSystemWindows = systemWindows;
+ mMainExecutor = mainExecutor;
+ mMainHandler = mainHandler;
+ mPipUiEventLogger = pipUiEventLogger;
+
+ mSurfaceControlTransactionFactory =
+ new PipSurfaceTransactionHelper.VsyncSurfaceControlTransactionFactory();
+ }
+
+ public boolean isMenuVisible() {
+ return mPipMenuView != null && mMenuState != MENU_STATE_NONE;
+ }
+
+ /**
+ * Attach the menu when the PiP task first appears.
+ */
+ @Override
+ public void attach(SurfaceControl leash) {
+ mLeash = leash;
+ attachPipMenuView();
+ }
+
+ /**
+ * Detach the menu when the PiP task is gone.
+ */
+ @Override
+ public void detach() {
+ hideMenu();
+ detachPipMenuView();
+ mLeash = null;
+ }
+
+ void attachPipMenuView() {
+ // In case detach was not called (e.g. PIP unexpectedly closed)
+ if (mPipMenuView != null) {
+ detachPipMenuView();
+ }
+ mPipMenuView = new PipMenuView(mContext, this, mMainExecutor, mMainHandler,
+ mPipUiEventLogger);
+ mPipMenuView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
+ @Override
+ public void onViewAttachedToWindow(View v) {
+ v.getViewRootImpl().addSurfaceChangedCallback(
+ new ViewRootImpl.SurfaceChangedCallback() {
+ @Override
+ public void surfaceCreated(SurfaceControl.Transaction t) {
+ final SurfaceControl sc = getSurfaceControl();
+ if (sc != null) {
+ t.reparent(sc, mLeash);
+ // make menu on top of the surface
+ t.setLayer(sc, Integer.MAX_VALUE);
+ }
+ }
+
+ @Override
+ public void surfaceReplaced(SurfaceControl.Transaction t) {
+ }
+
+ @Override
+ public void surfaceDestroyed() {
+ }
+ });
+ }
+
+ @Override
+ public void onViewDetachedFromWindow(View v) {
+ }
+ });
+
+ mSystemWindows.addView(mPipMenuView,
+ getPipMenuLayoutParams(mContext, MENU_WINDOW_TITLE, 0 /* width */, 0 /* height */),
+ 0, SHELL_ROOT_LAYER_PIP);
+ setShellRootAccessibilityWindow();
+
+ // Make sure the initial actions are set
+ updateMenuActions();
+ }
+
+ private void detachPipMenuView() {
+ if (mPipMenuView == null) {
+ return;
+ }
+
+ mSystemWindows.removeView(mPipMenuView);
+ mPipMenuView = null;
+ }
+
+ /**
+ * Updates the layout parameters of the menu.
+ * @param destinationBounds New Menu bounds.
+ */
+ @Override
+ public void updateMenuBounds(Rect destinationBounds) {
+ mSystemWindows.updateViewLayout(mPipMenuView,
+ getPipMenuLayoutParams(mContext, MENU_WINDOW_TITLE, destinationBounds.width(),
+ destinationBounds.height()));
+ updateMenuLayout(destinationBounds);
+ }
+
+ @Override
+ public void onFocusTaskChanged(ActivityManager.RunningTaskInfo taskInfo) {
+ if (mPipMenuView != null) {
+ mPipMenuView.onFocusTaskChanged(taskInfo);
+ }
+ }
+
+ /**
+ * Tries to grab a surface control from {@link PipMenuView}. If this isn't available for some
+ * reason (ie. the window isn't ready yet, thus {@link ViewRootImpl} is
+ * {@code null}), it will get the leash that the WindowlessWM has assigned to it.
+ */
+ public SurfaceControl getSurfaceControl() {
+ return mSystemWindows.getViewSurface(mPipMenuView);
+ }
+
+ /**
+ * Adds a new menu activity listener.
+ */
+ public void addListener(Listener listener) {
+ if (!mListeners.contains(listener)) {
+ mListeners.add(listener);
+ }
+ }
+
+ @Nullable
+ Size getEstimatedMinMenuSize() {
+ return mPipMenuView == null ? null : mPipMenuView.getEstimatedMinMenuSize();
+ }
+
+ /**
+ * When other components requests the menu controller directly to show the menu, we must
+ * first fire off the request to the other listeners who will then propagate the call
+ * back to the controller with the right parameters.
+ */
+ @Override
+ public void showMenu() {
+ mListeners.forEach(Listener::onPipShowMenu);
+ }
+
+ /**
+ * Similar to {@link #showMenu(int, Rect, boolean, boolean, boolean)} but only show the menu
+ * upon PiP window transition is finished.
+ */
+ public void showMenuWithPossibleDelay(int menuState, Rect stackBounds, boolean allowMenuTimeout,
+ boolean willResizeMenu, boolean showResizeHandle) {
+ if (willResizeMenu) {
+ // hide all visible controls including close button and etc. first, this is to ensure
+ // menu is totally invisible during the transition to eliminate unpleasant artifacts
+ fadeOutMenu();
+ }
+ showMenuInternal(menuState, stackBounds, allowMenuTimeout, willResizeMenu,
+ willResizeMenu /* withDelay=willResizeMenu here */, showResizeHandle);
+ }
+
+ /**
+ * Shows the menu activity immediately.
+ */
+ public void showMenu(int menuState, Rect stackBounds, boolean allowMenuTimeout,
+ boolean willResizeMenu, boolean showResizeHandle) {
+ showMenuInternal(menuState, stackBounds, allowMenuTimeout, willResizeMenu,
+ false /* withDelay */, showResizeHandle);
+ }
+
+ private void showMenuInternal(int menuState, Rect stackBounds, boolean allowMenuTimeout,
+ boolean willResizeMenu, boolean withDelay, boolean showResizeHandle) {
+ if (DEBUG) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: showMenu() state=%s"
+ + " isMenuVisible=%s"
+ + " allowMenuTimeout=%s"
+ + " willResizeMenu=%s"
+ + " withDelay=%s"
+ + " showResizeHandle=%s"
+ + " callers=\n%s", TAG, menuState, isMenuVisible(), allowMenuTimeout,
+ willResizeMenu, withDelay, showResizeHandle, Debug.getCallers(5, " "));
+ }
+
+ if (!checkPipMenuState()) {
+ return;
+ }
+
+ // Sync the menu bounds before showing it in case it is out of sync.
+ movePipMenu(null /* pipLeash */, null /* transaction */, stackBounds,
+ PipMenuController.ALPHA_NO_CHANGE);
+ updateMenuBounds(stackBounds);
+
+ mPipMenuView.showMenu(menuState, stackBounds, allowMenuTimeout, willResizeMenu, withDelay,
+ showResizeHandle);
+ }
+
+ /**
+ * Move the PiP menu, which does a translation and possibly a scale transformation.
+ */
+ @Override
+ public void movePipMenu(@Nullable SurfaceControl pipLeash,
+ @Nullable SurfaceControl.Transaction t,
+ Rect destinationBounds, float alpha) {
+ if (destinationBounds.isEmpty()) {
+ return;
+ }
+
+ if (!checkPipMenuState()) {
+ return;
+ }
+
+ // TODO(b/286307861) transaction should be applied outside of PiP menu controller
+ if (pipLeash != null && t != null) {
+ t.apply();
+ }
+ }
+
+ /**
+ * Does an immediate window crop of the PiP menu.
+ */
+ @Override
+ public void resizePipMenu(@Nullable SurfaceControl pipLeash,
+ @Nullable SurfaceControl.Transaction t,
+ Rect destinationBounds) {
+ if (destinationBounds.isEmpty()) {
+ return;
+ }
+
+ if (!checkPipMenuState()) {
+ return;
+ }
+
+ // TODO(b/286307861) transaction should be applied outside of PiP menu controller
+ if (pipLeash != null && t != null) {
+ t.apply();
+ }
+ }
+
+ private boolean checkPipMenuState() {
+ if (mPipMenuView == null || mPipMenuView.getViewRootImpl() == null) {
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: Not going to move PiP, either menu or its parent is not created.", TAG);
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Pokes the menu, indicating that the user is interacting with it.
+ */
+ public void pokeMenu() {
+ final boolean isMenuVisible = isMenuVisible();
+ if (DEBUG) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: pokeMenu() isMenuVisible=%b", TAG, isMenuVisible);
+ }
+ if (isMenuVisible) {
+ mPipMenuView.pokeMenu();
+ }
+ }
+
+ private void fadeOutMenu() {
+ final boolean isMenuVisible = isMenuVisible();
+ if (DEBUG) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: fadeOutMenu() isMenuVisible=%b", TAG, isMenuVisible);
+ }
+ if (isMenuVisible) {
+ mPipMenuView.fadeOutMenu();
+ }
+ }
+
+ /**
+ * Hides the menu view.
+ */
+ public void hideMenu() {
+ final boolean isMenuVisible = isMenuVisible();
+ if (isMenuVisible) {
+ mPipMenuView.hideMenu();
+ }
+ }
+
+ /**
+ * Hides the menu view.
+ *
+ * @param animationType the animation type to use upon hiding the menu
+ * @param resize whether or not to resize the PiP with the state change
+ */
+ public void hideMenu(@PipMenuView.AnimationType int animationType, boolean resize) {
+ final boolean isMenuVisible = isMenuVisible();
+ if (DEBUG) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: hideMenu() state=%s"
+ + " isMenuVisible=%s"
+ + " animationType=%s"
+ + " resize=%s"
+ + " callers=\n%s", TAG, mMenuState, isMenuVisible,
+ animationType, resize,
+ Debug.getCallers(5, " "));
+ }
+ if (isMenuVisible) {
+ mPipMenuView.hideMenu(resize, animationType);
+ }
+ }
+
+ /**
+ * Hides the menu activity.
+ */
+ public void hideMenu(Runnable onStartCallback, Runnable onEndCallback) {
+ if (isMenuVisible()) {
+ // If the menu is visible in either the closed or full state, then hide the menu and
+ // trigger the animation trigger afterwards
+ if (onStartCallback != null) {
+ onStartCallback.run();
+ }
+ mPipMenuView.hideMenu(onEndCallback);
+ }
+ }
+
+ /**
+ * Sets the menu actions to the actions provided by the current PiP menu.
+ */
+ @Override
+ public void setAppActions(List<RemoteAction> appActions,
+ RemoteAction closeAction) {
+ mAppActions = appActions;
+ mCloseAction = closeAction;
+ updateMenuActions();
+ }
+
+ void onPipExpand() {
+ mListeners.forEach(Listener::onPipExpand);
+ }
+
+ void onPipDismiss() {
+ mListeners.forEach(Listener::onPipDismiss);
+ }
+
+ void onEnterSplit() {
+ mListeners.forEach(Listener::onEnterSplit);
+ }
+
+ /**
+ * @return the best set of actions to show in the PiP menu.
+ */
+ private List<RemoteAction> resolveMenuActions() {
+ if (isValidActions(mAppActions)) {
+ return mAppActions;
+ }
+ return mMediaActions;
+ }
+
+ /**
+ * Updates the PiP menu with the best set of actions provided.
+ */
+ private void updateMenuActions() {
+ if (mPipMenuView != null) {
+ mPipMenuView.setActions(mPipBoundsState.getBounds(),
+ resolveMenuActions(), mCloseAction);
+ }
+ }
+
+ /**
+ * Returns whether the set of actions are valid.
+ */
+ private static boolean isValidActions(List<?> actions) {
+ return actions != null && actions.size() > 0;
+ }
+
+ /**
+ * Handles changes in menu visibility.
+ */
+ void onMenuStateChangeStart(int menuState, boolean resize, Runnable callback) {
+ if (DEBUG) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: onMenuStateChangeStart() mMenuState=%s"
+ + " menuState=%s resize=%s"
+ + " callers=\n%s", TAG, mMenuState, menuState, resize,
+ Debug.getCallers(5, " "));
+ }
+
+ if (menuState != mMenuState) {
+ mListeners.forEach(l -> l.onPipMenuStateChangeStart(menuState, resize, callback));
+ if (menuState == MENU_STATE_FULL) {
+ // Once visible, start listening for media action changes. This call will trigger
+ // the menu actions to be updated again.
+ mMediaController.addActionListener(mMediaActionListener);
+ } else {
+ // Once hidden, stop listening for media action changes. This call will trigger
+ // the menu actions to be updated again.
+ mMediaController.removeActionListener(mMediaActionListener);
+ }
+
+ try {
+ WindowManagerGlobal.getWindowSession().grantEmbeddedWindowFocus(null /* window */,
+ mSystemWindows.getFocusGrantToken(mPipMenuView),
+ menuState != MENU_STATE_NONE /* grantFocus */);
+ } catch (RemoteException e) {
+ ProtoLog.e(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: Unable to update focus as menu appears/disappears, %s", TAG, e);
+ }
+ }
+ }
+
+ void onMenuStateChangeFinish(int menuState) {
+ if (menuState != mMenuState) {
+ mListeners.forEach(l -> l.onPipMenuStateChangeFinish(menuState));
+ }
+ mMenuState = menuState;
+ setShellRootAccessibilityWindow();
+ }
+
+ private void setShellRootAccessibilityWindow() {
+ switch (mMenuState) {
+ case MENU_STATE_NONE:
+ mSystemWindows.setShellRootAccessibilityWindow(0, SHELL_ROOT_LAYER_PIP, null);
+ break;
+ default:
+ mSystemWindows.setShellRootAccessibilityWindow(0, SHELL_ROOT_LAYER_PIP,
+ mPipMenuView);
+ break;
+ }
+ }
+
+ /**
+ * Handles a pointer event sent from pip input consumer.
+ */
+ void handlePointerEvent(MotionEvent ev) {
+ if (mPipMenuView == null) {
+ return;
+ }
+
+ if (ev.isTouchEvent()) {
+ mPipMenuView.dispatchTouchEvent(ev);
+ } else {
+ mPipMenuView.dispatchGenericMotionEvent(ev);
+ }
+ }
+
+ /**
+ * Tell the PIP Menu to recalculate its layout given its current position on the display.
+ */
+ public void updateMenuLayout(Rect bounds) {
+ final boolean isMenuVisible = isMenuVisible();
+ if (DEBUG) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: updateMenuLayout() state=%s"
+ + " isMenuVisible=%s"
+ + " callers=\n%s", TAG, mMenuState, isMenuVisible,
+ Debug.getCallers(5, " "));
+ }
+ if (isMenuVisible) {
+ mPipMenuView.updateMenuLayout(bounds);
+ }
+ }
+
+ void dump(PrintWriter pw, String prefix) {
+ final String innerPrefix = prefix + " ";
+ pw.println(prefix + TAG);
+ pw.println(innerPrefix + "mMenuState=" + mMenuState);
+ pw.println(innerPrefix + "mPipMenuView=" + mPipMenuView);
+ pw.println(innerPrefix + "mListeners=" + mListeners.size());
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMenuActionView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMenuActionView.java
new file mode 100644
index 0000000..7252675
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMenuActionView.java
@@ -0,0 +1,56 @@
+/*
+ * 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.pip2.phone;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+
+import com.android.wm.shell.R;
+
+/**
+ * Container layout wraps single action image view drawn in PiP menu and can restrict the size of
+ * action image view (see pip_menu_action.xml).
+ */
+public class PipMenuActionView extends FrameLayout {
+ private ImageView mImageView;
+ private View mCustomCloseBackground;
+
+ public PipMenuActionView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ mImageView = findViewById(R.id.image);
+ mCustomCloseBackground = findViewById(R.id.custom_close_bg);
+ }
+
+ /** pass through to internal {@link #mImageView} */
+ public void setImageDrawable(Drawable drawable) {
+ mImageView.setImageDrawable(drawable);
+ }
+
+ /** pass through to internal {@link #mCustomCloseBackground} */
+ public void setCustomCloseBackgroundVisibility(@Visibility int visibility) {
+ mCustomCloseBackground.setVisibility(visibility);
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMenuIconsAlgorithm.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMenuIconsAlgorithm.java
new file mode 100644
index 0000000..b5e575b
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMenuIconsAlgorithm.java
@@ -0,0 +1,73 @@
+/*
+ * 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.pip2.phone;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+
+/**
+ * Helper class to calculate and place the menu icons on the PIP Menu.
+ */
+public class PipMenuIconsAlgorithm {
+
+ private static final String TAG = "PipMenuIconsAlgorithm";
+
+ protected ViewGroup mViewRoot;
+ protected ViewGroup mTopEndContainer;
+ protected View mDragHandle;
+ protected View mEnterSplitButton;
+ protected View mSettingsButton;
+ protected View mDismissButton;
+
+ protected PipMenuIconsAlgorithm(Context context) {
+ }
+
+ /**
+ * Bind the necessary views.
+ */
+ public void bindViews(ViewGroup viewRoot, ViewGroup topEndContainer, View dragHandle,
+ View enterSplitButton, View settingsButton, View dismissButton) {
+ mViewRoot = viewRoot;
+ mTopEndContainer = topEndContainer;
+ mDragHandle = dragHandle;
+ mEnterSplitButton = enterSplitButton;
+ mSettingsButton = settingsButton;
+ mDismissButton = dismissButton;
+ }
+
+ /**
+ * Updates the position of the drag handle based on where the PIP window is on the screen.
+ */
+ public void onBoundsChanged(Rect bounds) {
+ // On phones, the menu icons are always static and will never move based on the PIP window
+ // position. No need to do anything here.
+ }
+
+ /**
+ * Set the gravity on the given view.
+ */
+ protected static void setLayoutGravity(View v, int gravity) {
+ if (v.getLayoutParams() instanceof FrameLayout.LayoutParams) {
+ FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) v.getLayoutParams();
+ params.gravity = gravity;
+ v.setLayoutParams(params);
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMenuView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMenuView.java
new file mode 100644
index 0000000..a5b76c7
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMenuView.java
@@ -0,0 +1,630 @@
+/*
+ * 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.pip2.phone;
+
+import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK;
+import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
+import static android.provider.Settings.ACTION_PICTURE_IN_PICTURE_SETTINGS;
+import static android.view.accessibility.AccessibilityManager.FLAG_CONTENT_CONTROLS;
+import static android.view.accessibility.AccessibilityManager.FLAG_CONTENT_ICONS;
+import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLICK;
+
+import static com.android.wm.shell.pip.phone.PhonePipMenuController.MENU_STATE_FULL;
+import static com.android.wm.shell.pip.phone.PhonePipMenuController.MENU_STATE_NONE;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.ActivityManager;
+import android.app.PendingIntent;
+import android.app.RemoteAction;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Color;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.Icon;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.UserHandle;
+import android.util.Pair;
+import android.util.Size;
+import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.accessibility.AccessibilityManager;
+import android.view.accessibility.AccessibilityNodeInfo;
+import android.widget.FrameLayout;
+import android.widget.LinearLayout;
+
+import com.android.internal.protolog.common.ProtoLog;
+import com.android.wm.shell.R;
+import com.android.wm.shell.animation.Interpolators;
+import com.android.wm.shell.common.ShellExecutor;
+import com.android.wm.shell.common.pip.PipUiEventLogger;
+import com.android.wm.shell.common.pip.PipUtils;
+import com.android.wm.shell.protolog.ShellProtoLogGroup;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Translucent window that gets started on top of a task in PIP to allow the user to control it.
+ */
+public class PipMenuView extends FrameLayout {
+
+ private static final String TAG = "PipMenuView";
+
+ private static final int ANIMATION_NONE_DURATION_MS = 0;
+ private static final int ANIMATION_HIDE_DURATION_MS = 125;
+
+ /** No animation performed during menu hide. */
+ public static final int ANIM_TYPE_NONE = 0;
+ /** Fade out the menu until it's invisible. Used when the PIP window remains visible. */
+ public static final int ANIM_TYPE_HIDE = 1;
+ /** Fade out the menu in sync with the PIP window. */
+ public static final int ANIM_TYPE_DISMISS = 2;
+
+ @IntDef(prefix = { "ANIM_TYPE_" }, value = {
+ ANIM_TYPE_NONE,
+ ANIM_TYPE_HIDE,
+ ANIM_TYPE_DISMISS
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface AnimationType {}
+
+ private static final int INITIAL_DISMISS_DELAY = 3500;
+ private static final int POST_INTERACTION_DISMISS_DELAY = 2000;
+ private static final long MENU_SHOW_ON_EXPAND_START_DELAY = 30;
+
+ private static final float MENU_BACKGROUND_ALPHA = 0.54f;
+ private static final float DISABLED_ACTION_ALPHA = 0.54f;
+
+ private int mMenuState;
+ private boolean mAllowMenuTimeout = true;
+ private boolean mAllowTouches = true;
+ private int mDismissFadeOutDurationMs;
+ private final List<RemoteAction> mActions = new ArrayList<>();
+ private RemoteAction mCloseAction;
+
+ private AccessibilityManager mAccessibilityManager;
+ private Drawable mBackgroundDrawable;
+ private View mMenuContainer;
+ private LinearLayout mActionsGroup;
+ private int mBetweenActionPaddingLand;
+
+ private AnimatorSet mMenuContainerAnimator;
+ private final PhonePipMenuController mController;
+ private final PipUiEventLogger mPipUiEventLogger;
+
+ private ValueAnimator.AnimatorUpdateListener mMenuBgUpdateListener =
+ new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ final float alpha = (float) animation.getAnimatedValue();
+ mBackgroundDrawable.setAlpha((int) (MENU_BACKGROUND_ALPHA * alpha * 255));
+ }
+ };
+
+ private ShellExecutor mMainExecutor;
+ private Handler mMainHandler;
+
+ /**
+ * Whether the most recent showing of the menu caused a PIP resize, such as when PIP is too
+ * small and it is resized on menu show to fit the actions.
+ */
+ private boolean mDidLastShowMenuResize;
+ private final Runnable mHideMenuRunnable = this::hideMenu;
+
+ protected View mViewRoot;
+ protected View mSettingsButton;
+ protected View mDismissButton;
+ protected View mEnterSplitButton;
+ protected View mTopEndContainer;
+ protected PipMenuIconsAlgorithm mPipMenuIconsAlgorithm;
+
+ // How long the shell will wait for the app to close the PiP if a custom action is set.
+ private final int mPipForceCloseDelay;
+
+ public PipMenuView(Context context, PhonePipMenuController controller,
+ ShellExecutor mainExecutor, Handler mainHandler, PipUiEventLogger pipUiEventLogger) {
+ super(context, null, 0);
+ mContext = context;
+ mController = controller;
+ mMainExecutor = mainExecutor;
+ mMainHandler = mainHandler;
+ mPipUiEventLogger = pipUiEventLogger;
+
+ mAccessibilityManager = context.getSystemService(AccessibilityManager.class);
+ inflate(context, R.layout.pip_menu, this);
+
+ mPipForceCloseDelay = context.getResources().getInteger(
+ R.integer.config_pipForceCloseDelay);
+
+ mBackgroundDrawable = mContext.getDrawable(R.drawable.pip_menu_background);
+ mBackgroundDrawable.setAlpha(0);
+ mViewRoot = findViewById(R.id.background);
+ mViewRoot.setBackground(mBackgroundDrawable);
+ mMenuContainer = findViewById(R.id.menu_container);
+ mMenuContainer.setAlpha(0);
+ mTopEndContainer = findViewById(R.id.top_end_container);
+ mSettingsButton = findViewById(R.id.settings);
+ mSettingsButton.setAlpha(0);
+ mSettingsButton.setOnClickListener((v) -> {
+ if (v.getAlpha() != 0) {
+ showSettings();
+ }
+ });
+ mDismissButton = findViewById(R.id.dismiss);
+ mDismissButton.setAlpha(0);
+ mDismissButton.setOnClickListener(v -> dismissPip());
+ findViewById(R.id.expand_button).setOnClickListener(v -> {
+ if (mMenuContainer.getAlpha() != 0) {
+ expandPip();
+ }
+ });
+
+ mEnterSplitButton = findViewById(R.id.enter_split);
+ mEnterSplitButton.setAlpha(0);
+ mEnterSplitButton.setOnClickListener(v -> {
+ if (mEnterSplitButton.getAlpha() != 0) {
+ enterSplit();
+ }
+ });
+
+ // this disables the ripples
+ mEnterSplitButton.setEnabled(false);
+
+ findViewById(R.id.resize_handle).setAlpha(0);
+
+ mActionsGroup = findViewById(R.id.actions_group);
+ mBetweenActionPaddingLand = getResources().getDimensionPixelSize(
+ R.dimen.pip_between_action_padding_land);
+ mPipMenuIconsAlgorithm = new PipMenuIconsAlgorithm(mContext);
+ mPipMenuIconsAlgorithm.bindViews((ViewGroup) mViewRoot, (ViewGroup) mTopEndContainer,
+ findViewById(R.id.resize_handle), mEnterSplitButton, mSettingsButton,
+ mDismissButton);
+ mDismissFadeOutDurationMs = context.getResources()
+ .getInteger(R.integer.config_pipExitAnimationDuration);
+
+ initAccessibility();
+ }
+
+ private void initAccessibility() {
+ this.setAccessibilityDelegate(new AccessibilityDelegate() {
+ @Override
+ public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
+ super.onInitializeAccessibilityNodeInfo(host, info);
+ String label = getResources().getString(R.string.pip_menu_title);
+ info.addAction(new AccessibilityNodeInfo.AccessibilityAction(ACTION_CLICK, label));
+ }
+
+ @Override
+ public boolean performAccessibilityAction(View host, int action, Bundle args) {
+ if (action == ACTION_CLICK && mMenuState != MENU_STATE_FULL) {
+ mController.showMenu();
+ }
+ return super.performAccessibilityAction(host, action, args);
+ }
+ });
+ }
+
+ @Override
+ public boolean onKeyUp(int keyCode, KeyEvent event) {
+ if (keyCode == KeyEvent.KEYCODE_ESCAPE) {
+ hideMenu();
+ return true;
+ }
+ return super.onKeyUp(keyCode, event);
+ }
+
+ @Override
+ public boolean shouldDelayChildPressedState() {
+ return true;
+ }
+
+ @Override
+ public boolean dispatchTouchEvent(MotionEvent ev) {
+ if (!mAllowTouches) {
+ return false;
+ }
+
+ if (mAllowMenuTimeout) {
+ repostDelayedHide(POST_INTERACTION_DISMISS_DELAY);
+ }
+
+ return super.dispatchTouchEvent(ev);
+ }
+
+ @Override
+ public boolean dispatchGenericMotionEvent(MotionEvent event) {
+ if (mAllowMenuTimeout) {
+ repostDelayedHide(POST_INTERACTION_DISMISS_DELAY);
+ }
+
+ return super.dispatchGenericMotionEvent(event);
+ }
+
+ void onFocusTaskChanged(ActivityManager.RunningTaskInfo taskInfo) {}
+
+ void showMenu(int menuState, Rect stackBounds, boolean allowMenuTimeout,
+ boolean resizeMenuOnShow, boolean withDelay, boolean showResizeHandle) {
+ mAllowMenuTimeout = allowMenuTimeout;
+ mDidLastShowMenuResize = resizeMenuOnShow;
+ final boolean enableEnterSplit =
+ mContext.getResources().getBoolean(R.bool.config_pipEnableEnterSplitButton);
+ if (mMenuState != menuState) {
+ // Disallow touches if the menu needs to resize while showing, and we are transitioning
+ // to/from a full menu state.
+ boolean disallowTouchesUntilAnimationEnd = resizeMenuOnShow
+ && (mMenuState == MENU_STATE_FULL || menuState == MENU_STATE_FULL);
+ mAllowTouches = !disallowTouchesUntilAnimationEnd;
+ cancelDelayedHide();
+ if (mMenuContainerAnimator != null) {
+ mMenuContainerAnimator.cancel();
+ }
+ mMenuContainerAnimator = new AnimatorSet();
+ ObjectAnimator menuAnim = ObjectAnimator.ofFloat(mMenuContainer, View.ALPHA,
+ mMenuContainer.getAlpha(), 1f);
+ menuAnim.addUpdateListener(mMenuBgUpdateListener);
+ ObjectAnimator settingsAnim = ObjectAnimator.ofFloat(mSettingsButton, View.ALPHA,
+ mSettingsButton.getAlpha(), 1f);
+ ObjectAnimator dismissAnim = ObjectAnimator.ofFloat(mDismissButton, View.ALPHA,
+ mDismissButton.getAlpha(), 1f);
+ if (menuState == MENU_STATE_FULL) {
+ mMenuContainerAnimator.playTogether(menuAnim, settingsAnim, dismissAnim);
+ }
+ mMenuContainerAnimator.setInterpolator(Interpolators.ALPHA_IN);
+ mMenuContainerAnimator.setDuration(ANIMATION_HIDE_DURATION_MS);
+ mMenuContainerAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mAllowTouches = true;
+ notifyMenuStateChangeFinish(menuState);
+ if (allowMenuTimeout) {
+ repostDelayedHide(INITIAL_DISMISS_DELAY);
+ }
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ mAllowTouches = true;
+ }
+ });
+ if (withDelay) {
+ // starts the menu container animation after window expansion is completed
+ notifyMenuStateChangeStart(menuState, resizeMenuOnShow, () -> {
+ if (mMenuContainerAnimator == null) {
+ return;
+ }
+ mMenuContainerAnimator.setStartDelay(MENU_SHOW_ON_EXPAND_START_DELAY);
+ setVisibility(VISIBLE);
+ mMenuContainerAnimator.start();
+ });
+ } else {
+ notifyMenuStateChangeStart(menuState, resizeMenuOnShow, null);
+ setVisibility(VISIBLE);
+ mMenuContainerAnimator.start();
+ }
+ updateActionViews(menuState, stackBounds);
+ } else {
+ // If we are already visible, then just start the delayed dismiss and unregister any
+ // existing input consumers from the previous drag
+ if (allowMenuTimeout) {
+ repostDelayedHide(POST_INTERACTION_DISMISS_DELAY);
+ }
+ }
+ }
+
+ /**
+ * Different from {@link #hideMenu()}, this function does not try to finish this menu activity
+ * and instead, it fades out the controls by setting the alpha to 0 directly without menu
+ * visibility callbacks invoked.
+ */
+ void fadeOutMenu() {
+ mMenuContainer.setAlpha(0f);
+ mSettingsButton.setAlpha(0f);
+ mDismissButton.setAlpha(0f);
+ mEnterSplitButton.setAlpha(0f);
+ }
+
+ void pokeMenu() {
+ cancelDelayedHide();
+ }
+
+ void updateMenuLayout(Rect bounds) {
+ mPipMenuIconsAlgorithm.onBoundsChanged(bounds);
+ }
+
+ void hideMenu() {
+ hideMenu(null);
+ }
+
+ void hideMenu(Runnable animationEndCallback) {
+ hideMenu(animationEndCallback, true /* notifyMenuVisibility */, mDidLastShowMenuResize,
+ ANIM_TYPE_HIDE);
+ }
+
+ void hideMenu(boolean resize, @AnimationType int animationType) {
+ hideMenu(null /* animationFinishedRunnable */, true /* notifyMenuVisibility */, resize,
+ animationType);
+ }
+
+ void hideMenu(final Runnable animationFinishedRunnable, boolean notifyMenuVisibility,
+ boolean resize, @AnimationType int animationType) {
+ if (mMenuState != MENU_STATE_NONE) {
+ cancelDelayedHide();
+ if (notifyMenuVisibility) {
+ notifyMenuStateChangeStart(MENU_STATE_NONE, resize, null);
+ }
+ mMenuContainerAnimator = new AnimatorSet();
+ ObjectAnimator menuAnim = ObjectAnimator.ofFloat(mMenuContainer, View.ALPHA,
+ mMenuContainer.getAlpha(), 0f);
+ menuAnim.addUpdateListener(mMenuBgUpdateListener);
+ ObjectAnimator settingsAnim = ObjectAnimator.ofFloat(mSettingsButton, View.ALPHA,
+ mSettingsButton.getAlpha(), 0f);
+ ObjectAnimator dismissAnim = ObjectAnimator.ofFloat(mDismissButton, View.ALPHA,
+ mDismissButton.getAlpha(), 0f);
+ ObjectAnimator enterSplitAnim = ObjectAnimator.ofFloat(mEnterSplitButton, View.ALPHA,
+ mEnterSplitButton.getAlpha(), 0f);
+ mMenuContainerAnimator.playTogether(menuAnim, settingsAnim, dismissAnim,
+ enterSplitAnim);
+ mMenuContainerAnimator.setInterpolator(Interpolators.ALPHA_OUT);
+ mMenuContainerAnimator.setDuration(getFadeOutDuration(animationType));
+ mMenuContainerAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ setVisibility(GONE);
+ if (notifyMenuVisibility) {
+ notifyMenuStateChangeFinish(MENU_STATE_NONE);
+ }
+ if (animationFinishedRunnable != null) {
+ animationFinishedRunnable.run();
+ }
+ }
+ });
+ mMenuContainerAnimator.start();
+ }
+ }
+
+ /**
+ * @return Estimated minimum {@link Size} to hold the actions.
+ * See also {@link #updateActionViews(Rect)}
+ */
+ Size getEstimatedMinMenuSize() {
+ final int pipActionSize = getResources().getDimensionPixelSize(R.dimen.pip_action_size);
+ // the minimum width would be (2 * pipActionSize) since we have settings and dismiss button
+ // on the top action container.
+ final int width = Math.max(2, mActions.size()) * pipActionSize;
+ final int height = getResources().getDimensionPixelSize(R.dimen.pip_expand_action_size)
+ + getResources().getDimensionPixelSize(R.dimen.pip_action_padding)
+ + getResources().getDimensionPixelSize(R.dimen.pip_expand_container_edge_margin);
+ return new Size(width, height);
+ }
+
+ void setActions(Rect stackBounds, @Nullable List<RemoteAction> actions,
+ @Nullable RemoteAction closeAction) {
+ mActions.clear();
+ if (actions != null && !actions.isEmpty()) {
+ mActions.addAll(actions);
+ }
+ mCloseAction = closeAction;
+ if (mMenuState == MENU_STATE_FULL) {
+ updateActionViews(mMenuState, stackBounds);
+ }
+ }
+
+ private void updateActionViews(int menuState, Rect stackBounds) {
+ ViewGroup expandContainer = findViewById(R.id.expand_container);
+ ViewGroup actionsContainer = findViewById(R.id.actions_container);
+ actionsContainer.setOnTouchListener((v, ev) -> {
+ // Do nothing, prevent click through to parent
+ return true;
+ });
+
+ // Update the expand button only if it should show with the menu
+ expandContainer.setVisibility(menuState == MENU_STATE_FULL
+ ? View.VISIBLE
+ : View.INVISIBLE);
+
+ LayoutParams expandedLp =
+ (LayoutParams) expandContainer.getLayoutParams();
+ if (mActions.isEmpty() || menuState == MENU_STATE_NONE) {
+ actionsContainer.setVisibility(View.INVISIBLE);
+
+ // Update the expand container margin to adjust the center of the expand button to
+ // account for the existence of the action container
+ expandedLp.topMargin = 0;
+ expandedLp.bottomMargin = 0;
+ } else {
+ actionsContainer.setVisibility(View.VISIBLE);
+ if (mActionsGroup != null) {
+ // Ensure we have as many buttons as actions
+ final LayoutInflater inflater = LayoutInflater.from(mContext);
+ while (mActionsGroup.getChildCount() < mActions.size()) {
+ final PipMenuActionView actionView = (PipMenuActionView) inflater.inflate(
+ R.layout.pip_menu_action, mActionsGroup, false);
+ mActionsGroup.addView(actionView);
+ }
+
+ // Update the visibility of all views
+ for (int i = 0; i < mActionsGroup.getChildCount(); i++) {
+ mActionsGroup.getChildAt(i).setVisibility(i < mActions.size()
+ ? View.VISIBLE
+ : View.GONE);
+ }
+
+ // Recreate the layout
+ final boolean isLandscapePip = stackBounds != null
+ && (stackBounds.width() > stackBounds.height());
+ for (int i = 0; i < mActions.size(); i++) {
+ final RemoteAction action = mActions.get(i);
+ final PipMenuActionView actionView =
+ (PipMenuActionView) mActionsGroup.getChildAt(i);
+ final boolean isCloseAction = mCloseAction != null && Objects.equals(
+ mCloseAction.getActionIntent(), action.getActionIntent());
+
+ final int iconType = action.getIcon().getType();
+ if (iconType == Icon.TYPE_URI || iconType == Icon.TYPE_URI_ADAPTIVE_BITMAP) {
+ // Disallow loading icon from content URI
+ actionView.setImageDrawable(null);
+ } else {
+ // TODO: Check if the action drawable has changed before we reload it
+ action.getIcon().loadDrawableAsync(mContext, d -> {
+ if (d != null) {
+ d.setTint(Color.WHITE);
+ actionView.setImageDrawable(d);
+ }
+ }, mMainHandler);
+ }
+ actionView.setCustomCloseBackgroundVisibility(
+ isCloseAction ? View.VISIBLE : View.GONE);
+ actionView.setContentDescription(action.getContentDescription());
+ if (action.isEnabled()) {
+ actionView.setOnClickListener(
+ v -> onActionViewClicked(action.getActionIntent(), isCloseAction));
+ }
+ actionView.setEnabled(action.isEnabled());
+ actionView.setAlpha(action.isEnabled() ? 1f : DISABLED_ACTION_ALPHA);
+
+ // Update the margin between actions
+ LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)
+ actionView.getLayoutParams();
+ lp.leftMargin = (isLandscapePip && i > 0) ? mBetweenActionPaddingLand : 0;
+ }
+ }
+
+ // Update the expand container margin to adjust the center of the expand button to
+ // account for the existence of the action container
+ expandedLp.topMargin = getResources().getDimensionPixelSize(
+ R.dimen.pip_action_padding);
+ expandedLp.bottomMargin = getResources().getDimensionPixelSize(
+ R.dimen.pip_expand_container_edge_margin);
+ }
+ expandContainer.requestLayout();
+ }
+
+ private void notifyMenuStateChangeStart(int menuState, boolean resize, Runnable callback) {
+ mController.onMenuStateChangeStart(menuState, resize, callback);
+ }
+
+ private void notifyMenuStateChangeFinish(int menuState) {
+ mMenuState = menuState;
+ mController.onMenuStateChangeFinish(menuState);
+ }
+
+ private void expandPip() {
+ // Do not notify menu visibility when hiding the menu, the controller will do this when it
+ // handles the message
+ hideMenu(mController::onPipExpand, false /* notifyMenuVisibility */, true /* resize */,
+ ANIM_TYPE_HIDE);
+ mPipUiEventLogger.log(
+ PipUiEventLogger.PipUiEventEnum.PICTURE_IN_PICTURE_EXPAND_TO_FULLSCREEN);
+ }
+
+ private void dismissPip() {
+ if (mMenuState != MENU_STATE_NONE) {
+ // Do not call hideMenu() directly. Instead, let the menu controller handle it just as
+ // any other dismissal that will update the touch state and fade out the PIP task
+ // and the menu view at the same time.
+ mController.onPipDismiss();
+ mPipUiEventLogger.log(PipUiEventLogger.PipUiEventEnum.PICTURE_IN_PICTURE_TAP_TO_REMOVE);
+ }
+ }
+
+ /**
+ * Execute the {@link PendingIntent} attached to the {@link PipMenuActionView}.
+ * If the given {@link PendingIntent} matches {@link #mCloseAction}, we need to make sure
+ * the PiP is removed after a certain timeout in case the app does not respond in a
+ * timely manner.
+ */
+ private void onActionViewClicked(@NonNull PendingIntent intent, boolean isCloseAction) {
+ try {
+ intent.send();
+ } catch (PendingIntent.CanceledException e) {
+ ProtoLog.w(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "%s: Failed to send action, %s", TAG, e);
+ }
+ if (isCloseAction) {
+ mPipUiEventLogger.log(PipUiEventLogger.PipUiEventEnum.PICTURE_IN_PICTURE_CUSTOM_CLOSE);
+ mAllowTouches = false;
+ mMainExecutor.executeDelayed(() -> {
+ hideMenu();
+ // TODO: it's unsafe to call onPipDismiss with a delay here since
+ // we may have a different PiP by the time this runnable is executed.
+ mController.onPipDismiss();
+ mAllowTouches = true;
+ }, mPipForceCloseDelay);
+ }
+ }
+
+ private void enterSplit() {
+ // Do not notify menu visibility when hiding the menu, the controller will do this when it
+ // handles the message
+ hideMenu(mController::onEnterSplit, false /* notifyMenuVisibility */, true /* resize */,
+ ANIM_TYPE_HIDE);
+ }
+
+
+ private void showSettings() {
+ final Pair<ComponentName, Integer> topPipActivityInfo =
+ PipUtils.getTopPipActivity(mContext);
+ if (topPipActivityInfo.first != null) {
+ final Intent settingsIntent = new Intent(ACTION_PICTURE_IN_PICTURE_SETTINGS,
+ Uri.fromParts("package", topPipActivityInfo.first.getPackageName(), null));
+ settingsIntent.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK);
+ mContext.startActivityAsUser(settingsIntent, UserHandle.of(topPipActivityInfo.second));
+ mPipUiEventLogger.log(PipUiEventLogger.PipUiEventEnum.PICTURE_IN_PICTURE_SHOW_SETTINGS);
+ }
+ }
+
+ private void cancelDelayedHide() {
+ mMainExecutor.removeCallbacks(mHideMenuRunnable);
+ }
+
+ private void repostDelayedHide(int delay) {
+ int recommendedTimeout = mAccessibilityManager.getRecommendedTimeoutMillis(delay,
+ FLAG_CONTENT_ICONS | FLAG_CONTENT_CONTROLS);
+ mMainExecutor.removeCallbacks(mHideMenuRunnable);
+ mMainExecutor.executeDelayed(mHideMenuRunnable, recommendedTimeout);
+ }
+
+ private long getFadeOutDuration(@AnimationType int animationType) {
+ switch (animationType) {
+ case ANIM_TYPE_NONE:
+ return ANIMATION_NONE_DURATION_MS;
+ case ANIM_TYPE_HIDE:
+ return ANIMATION_HIDE_DURATION_MS;
+ case ANIM_TYPE_DISMISS:
+ return mDismissFadeOutDurationMs;
+ default:
+ throw new IllegalStateException("Invalid animation type " + animationType);
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java
index f3d178a..fbf4d13 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java
@@ -42,8 +42,8 @@
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.pip.PipBoundsAlgorithm;
import com.android.wm.shell.common.pip.PipBoundsState;
+import com.android.wm.shell.common.pip.PipMenuController;
import com.android.wm.shell.common.pip.PipUtils;
-import com.android.wm.shell.pip.PipMenuController;
import com.android.wm.shell.pip.PipTransitionController;
import com.android.wm.shell.sysui.ShellInit;
import com.android.wm.shell.transition.Transitions;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java
index e6faa63..96eaa1e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java
@@ -287,7 +287,7 @@
}
boolean isHandlingDragResize() {
- return mDragResizeListener.isHandlingDragResize();
+ return mDragResizeListener != null && mDragResizeListener.isHandlingDragResize();
}
private void closeDragResizeListener() {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
index 4ba05ce..1f7cc5a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
@@ -345,7 +345,7 @@
mTaskOperations.injectBackKey();
} else if (id == R.id.caption_handle || id == R.id.open_menu_button) {
if (!decoration.isHandleMenuActive()) {
- moveTaskToFront(mTaskOrganizer.getRunningTaskInfo(mTaskId));
+ moveTaskToFront(decoration.mTaskInfo);
decoration.createHandleMenu();
} else {
decoration.closeHandleMenu();
@@ -419,10 +419,10 @@
&& id != R.id.maximize_window) {
return false;
}
- moveTaskToFront(mTaskOrganizer.getRunningTaskInfo(mTaskId));
+ final DesktopModeWindowDecoration decoration = mWindowDecorByTaskId.get(mTaskId);
+ moveTaskToFront(decoration.mTaskInfo);
if (!mHasLongClicked && id != R.id.maximize_window) {
- final DesktopModeWindowDecoration decoration = mWindowDecorByTaskId.get(mTaskId);
decoration.closeMaximizeMenuIfNeeded(e);
}
@@ -466,7 +466,8 @@
*/
@Override
public boolean handleMotionEvent(@Nullable View v, MotionEvent e) {
- final RunningTaskInfo taskInfo = mTaskOrganizer.getRunningTaskInfo(mTaskId);
+ final DesktopModeWindowDecoration decoration = mWindowDecorByTaskId.get(mTaskId);
+ final RunningTaskInfo taskInfo = decoration.mTaskInfo;
if (DesktopModeStatus.isEnabled()
&& taskInfo.getWindowingMode() == WINDOWING_MODE_FULLSCREEN) {
return false;
@@ -492,8 +493,6 @@
}
case MotionEvent.ACTION_MOVE: {
mShouldClick = false;
- final DesktopModeWindowDecoration decoration =
- mWindowDecorByTaskId.get(mTaskId);
// If a decor's resize drag zone is active, don't also try to reposition it.
if (decoration.isHandlingDragResize()) break;
decoration.closeMaximizeMenu();
@@ -557,9 +556,10 @@
&& action != MotionEvent.ACTION_CANCEL)) {
return false;
}
- final RunningTaskInfo taskInfo = mTaskOrganizer.getRunningTaskInfo(mTaskId);
- mDesktopTasksController.ifPresent(c -> c.toggleDesktopTaskSize(taskInfo,
- mWindowDecorByTaskId.get(taskInfo.taskId)));
+ mDesktopTasksController.ifPresent(c -> {
+ final DesktopModeWindowDecoration decoration = mWindowDecorByTaskId.get(mTaskId);
+ c.toggleDesktopTaskSize(decoration.mTaskInfo, decoration);
+ });
return true;
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
index 2023333..3f0a281 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
@@ -36,7 +36,6 @@
import android.graphics.Region;
import android.graphics.drawable.Drawable;
import android.os.Handler;
-import android.util.Log;
import android.view.Choreographer;
import android.view.MotionEvent;
import android.view.SurfaceControl;
@@ -388,27 +387,20 @@
}
boolean isHandlingDragResize() {
- return mDragResizeListener.isHandlingDragResize();
+ return mDragResizeListener != null && mDragResizeListener.isHandlingDragResize();
}
private void loadAppInfo() {
- String packageName = mTaskInfo.realActivity.getPackageName();
PackageManager pm = mContext.getApplicationContext().getPackageManager();
- try {
- final IconProvider provider = new IconProvider(mContext);
- mAppIconDrawable = provider.getIcon(pm.getActivityInfo(mTaskInfo.baseActivity,
- PackageManager.ComponentInfoFlags.of(0)));
- final Resources resources = mContext.getResources();
- final BaseIconFactory factory = new BaseIconFactory(mContext,
- resources.getDisplayMetrics().densityDpi,
- resources.getDimensionPixelSize(R.dimen.desktop_mode_caption_icon_radius));
- mAppIconBitmap = factory.createScaledBitmap(mAppIconDrawable, MODE_DEFAULT);
- final ApplicationInfo applicationInfo = pm.getApplicationInfo(packageName,
- PackageManager.ApplicationInfoFlags.of(0));
- mAppName = pm.getApplicationLabel(applicationInfo);
- } catch (PackageManager.NameNotFoundException e) {
- Log.w(TAG, "Package not found: " + packageName, e);
- }
+ final IconProvider provider = new IconProvider(mContext);
+ mAppIconDrawable = provider.getIcon(mTaskInfo.topActivityInfo);
+ final Resources resources = mContext.getResources();
+ final BaseIconFactory factory = new BaseIconFactory(mContext,
+ resources.getDisplayMetrics().densityDpi,
+ resources.getDimensionPixelSize(R.dimen.desktop_mode_caption_icon_radius));
+ mAppIconBitmap = factory.createScaledBitmap(mAppIconDrawable, MODE_DEFAULT);
+ final ApplicationInfo applicationInfo = mTaskInfo.topActivityInfo.applicationInfo;
+ mAppName = pm.getApplicationLabel(applicationInfo);
}
private void closeDragResizeListener() {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java
index 8b38f99..d902621 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java
@@ -353,6 +353,7 @@
private boolean mShouldHandleEvents;
private int mLastCursorType = PointerIcon.TYPE_DEFAULT;
private Rect mDragStartTaskBounds;
+ private final Rect mTmpRect = new Rect();
private TaskResizeInputEventReceiver(
InputChannel inputChannel, Handler handler, Choreographer choreographer) {
@@ -477,14 +478,15 @@
}
private void updateInputSinkRegionForDrag(Rect taskBounds) {
+ mTmpRect.set(taskBounds);
final DisplayLayout layout = mDisplayController.getDisplayLayout(mDisplayId);
final Region dragTouchRegion = new Region(-taskBounds.left,
-taskBounds.top,
-taskBounds.left + layout.width(),
-taskBounds.top + layout.height());
// Remove the localized task bounds from the touch region.
- taskBounds.offsetTo(0, 0);
- dragTouchRegion.op(taskBounds, Region.Op.DIFFERENCE);
+ mTmpRect.offsetTo(0, 0);
+ dragTouchRegion.op(mTmpRect, Region.Op.DIFFERENCE);
updateSinkInputChannel(dragTouchRegion);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/ResizeVeil.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/ResizeVeil.java
index 368231e..b0d3b50 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/ResizeVeil.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/ResizeVeil.java
@@ -125,6 +125,7 @@
relayout(taskBounds, t);
if (fadeIn) {
+ cancelAnimation();
mVeilAnimator = new ValueAnimator();
mVeilAnimator.setFloatValues(0f, 1f);
mVeilAnimator.setDuration(RESIZE_ALPHA_DURATION);
@@ -210,15 +211,16 @@
* Animate veil's alpha to 0, fading it out.
*/
public void hideVeil() {
- final ValueAnimator animator = new ValueAnimator();
- animator.setFloatValues(1, 0);
- animator.setDuration(RESIZE_ALPHA_DURATION);
- animator.addUpdateListener(animation -> {
+ cancelAnimation();
+ mVeilAnimator = new ValueAnimator();
+ mVeilAnimator.setFloatValues(1, 0);
+ mVeilAnimator.setDuration(RESIZE_ALPHA_DURATION);
+ mVeilAnimator.addUpdateListener(animation -> {
SurfaceControl.Transaction t = mSurfaceControlTransactionSupplier.get();
- t.setAlpha(mVeilSurface, 1 - animator.getAnimatedFraction());
+ t.setAlpha(mVeilSurface, 1 - mVeilAnimator.getAnimatedFraction());
t.apply();
});
- animator.addListener(new AnimatorListenerAdapter() {
+ mVeilAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
SurfaceControl.Transaction t = mSurfaceControlTransactionSupplier.get();
@@ -226,7 +228,7 @@
t.apply();
}
});
- animator.start();
+ mVeilAnimator.start();
}
@ColorRes
@@ -240,10 +242,20 @@
}
}
+ private void cancelAnimation() {
+ if (mVeilAnimator != null) {
+ mVeilAnimator.removeAllUpdateListeners();
+ mVeilAnimator.cancel();
+ }
+ }
+
/**
* Dispose of veil when it is no longer needed, likely on close of its container decor.
*/
void dispose() {
+ cancelAnimation();
+ mVeilAnimator = null;
+
if (mViewHost != null) {
mViewHost.release();
mViewHost = null;
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/Android.bp b/libs/WindowManager/Shell/tests/flicker/pip/Android.bp
index e61f762..faeb342 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/Android.bp
+++ b/libs/WindowManager/Shell/tests/flicker/pip/Android.bp
@@ -30,6 +30,7 @@
"src/**/B*.kt",
"src/**/C*.kt",
"src/**/D*.kt",
+ "src/**/F*.kt",
"src/**/S*.kt",
],
}
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipFromSplitScreenOnGoToHomeTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/FromSplitScreenAutoEnterPipOnGoToHomeTest.kt
similarity index 92%
rename from libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipFromSplitScreenOnGoToHomeTest.kt
rename to libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/FromSplitScreenAutoEnterPipOnGoToHomeTest.kt
index a5c2c89..2792298 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipFromSplitScreenOnGoToHomeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/FromSplitScreenAutoEnterPipOnGoToHomeTest.kt
@@ -17,7 +17,6 @@
package com.android.wm.shell.flicker.pip
import android.platform.test.annotations.Presubmit
-import android.tools.common.NavBar
import android.tools.common.Rotation
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
@@ -62,7 +61,7 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class AutoEnterPipFromSplitScreenOnGoToHomeTest(flicker: LegacyFlickerTest) :
+class FromSplitScreenAutoEnterPipOnGoToHomeTest(flicker: LegacyFlickerTest) :
AutoEnterPipOnGoToHomeTest(flicker) {
private val portraitDisplayBounds = WindowUtils.getDisplayBounds(Rotation.ROTATION_0)
/** Second app used to enter split screen mode */
@@ -120,9 +119,7 @@
@Presubmit
@Test
override fun pipAppLayerAlwaysVisible() {
- // pip layer in gesture nav will disappear during transition with alpha animation
- Assume.assumeFalse(flicker.scenario.isGesturalNavigation)
- super.pipAppLayerAlwaysVisible()
+ // pip layer in should disappear during transition with alpha animation
}
@Presubmit
@@ -151,8 +148,7 @@
@JvmStatic
fun getParams() =
LegacyFlickerTestFactory.nonRotationTests(
- // TODO(b/176061063):The 3 buttons of nav bar do not exist in the hierarchy.
- supportedNavigationModes = listOf(NavBar.MODE_GESTURAL)
+ supportedRotations = listOf(Rotation.ROTATION_0)
)
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipFromSplitScreenOnGoToHomeTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/FromSplitScreenEnterPipOnUserLeaveHintTest.kt
similarity index 72%
copy from libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipFromSplitScreenOnGoToHomeTest.kt
copy to libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/FromSplitScreenEnterPipOnUserLeaveHintTest.kt
index a5c2c89..4c23153 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipFromSplitScreenOnGoToHomeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/FromSplitScreenEnterPipOnUserLeaveHintTest.kt
@@ -17,7 +17,6 @@
package com.android.wm.shell.flicker.pip
import android.platform.test.annotations.Presubmit
-import android.tools.common.NavBar
import android.tools.common.Rotation
import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
import android.tools.device.flicker.legacy.FlickerBuilder
@@ -28,6 +27,7 @@
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.helpers.SimpleAppHelper
import com.android.server.wm.flicker.testapp.ActivityOptions
+import com.android.wm.shell.flicker.pip.common.EnterPipTransition
import com.android.wm.shell.flicker.utils.SplitScreenUtils
import org.junit.Assume
import org.junit.FixMethodOrder
@@ -62,8 +62,8 @@
@RunWith(Parameterized::class)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class AutoEnterPipFromSplitScreenOnGoToHomeTest(flicker: LegacyFlickerTest) :
- AutoEnterPipOnGoToHomeTest(flicker) {
+class FromSplitScreenEnterPipOnUserLeaveHintTest(flicker: LegacyFlickerTest) :
+ EnterPipTransition(flicker) {
private val portraitDisplayBounds = WindowUtils.getDisplayBounds(Rotation.ROTATION_0)
/** Second app used to enter split screen mode */
private val secondAppForSplitScreen =
@@ -88,7 +88,7 @@
secondAppForSplitScreen,
flicker.scenario.startRotation
)
- pipApp.enableAutoEnterForPipActivity()
+ pipApp.enableEnterPipOnUserLeaveHint()
}
teardown {
pipApp.exit(wmHelper)
@@ -120,9 +120,44 @@
@Presubmit
@Test
override fun pipAppLayerAlwaysVisible() {
- // pip layer in gesture nav will disappear during transition with alpha animation
+ // pip layer in should disappear during transition with alpha animation
+ }
+
+ @Presubmit
+ @Test
+ override fun focusChanges() {
+ // in gestural nav the focus goes to different activity on swipe up
Assume.assumeFalse(flicker.scenario.isGesturalNavigation)
- super.pipAppLayerAlwaysVisible()
+ super.focusChanges()
+ }
+
+ @Presubmit
+ @Test
+ fun pipAppWindowVisibleChanges() {
+ // TODO(b/322394235) this method comes from EnterPipOnUserLeaveHintTest, but due to how
+ // it is being packaged in Android.bp we cannot inherit from it. Needs to be refactored.
+ Assume.assumeTrue(flicker.scenario.isGesturalNavigation)
+ flicker.assertWm {
+ this.isAppWindowVisible(pipApp)
+ .then()
+ .isAppWindowInvisible(pipApp, isOptional = true)
+ .then()
+ .isAppWindowVisible(pipApp, isOptional = true)
+ }
+ }
+
+ @Presubmit
+ @Test
+ override fun pipAppWindowAlwaysVisible() {
+ // TODO(b/322394235) this method comes from EnterPipOnUserLeaveHintTest, but due to how
+ // it is being packaged in Android.bp we cannot inherit from it. Needs to be refactored.
+ // In gestural nav the pip will first move behind home and then above home. The visual
+ // appearance visible->invisible->visible is asserted by pipAppLayerAlwaysVisible().
+ // But the internal states of activity don't need to follow that, such as a temporary
+ // visibility state can be changed quickly outside a transaction so the test doesn't
+ // detect that. Hence, skip the case to avoid restricting the internal implementation.
+ Assume.assumeFalse(flicker.scenario.isGesturalNavigation)
+ super.pipAppWindowAlwaysVisible()
}
@Presubmit
@@ -149,10 +184,8 @@
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
- fun getParams() =
- LegacyFlickerTestFactory.nonRotationTests(
- // TODO(b/176061063):The 3 buttons of nav bar do not exist in the hierarchy.
- supportedNavigationModes = listOf(NavBar.MODE_GESTURAL)
- )
+ fun getParams() = LegacyFlickerTestFactory.nonRotationTests(
+ supportedRotations = listOf(Rotation.ROTATION_0)
+ )
}
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java
index 193f16d..40e61dd 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java
@@ -27,6 +27,8 @@
import android.app.ActivityManager;
import android.content.ComponentName;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.TypedArray;
@@ -202,6 +204,8 @@
.setTaskDescriptionBuilder(taskDescriptionBuilder)
.setVisible(visible)
.build();
+ taskInfo.topActivityInfo = new ActivityInfo();
+ taskInfo.topActivityInfo.applicationInfo = new ApplicationInfo();
taskInfo.realActivity = new ComponentName("com.android.wm.shell.windowdecor",
"DesktopModeWindowDecorationTests");
taskInfo.baseActivity = new ComponentName("com.android.wm.shell.windowdecor",
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index 0abb6f5..4e330da 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -629,14 +629,6 @@
// Allow implicit fallthroughs in HardwareBitmapUploader.cpp until they are fixed.
cflags: ["-Wno-implicit-fallthrough"],
},
- host: {
- srcs: [
- "utils/HostColorSpace.cpp",
- ],
- export_static_lib_headers: [
- "libarect",
- ],
- },
},
}
diff --git a/libs/hwui/utils/HostColorSpace.cpp b/libs/hwui/utils/HostColorSpace.cpp
deleted file mode 100644
index 77a6820..0000000
--- a/libs/hwui/utils/HostColorSpace.cpp
+++ /dev/null
@@ -1,417 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-// This is copied from framework/native/libs/ui in order not to include libui in host build
-
-#include <ui/ColorSpace.h>
-
-using namespace std::placeholders;
-
-namespace android {
-
-static constexpr float linearResponse(float v) {
- return v;
-}
-
-static constexpr float rcpResponse(float x, const ColorSpace::TransferParameters& p) {
- return x >= p.d * p.c ? (std::pow(x, 1.0f / p.g) - p.b) / p.a : x / p.c;
-}
-
-static constexpr float response(float x, const ColorSpace::TransferParameters& p) {
- return x >= p.d ? std::pow(p.a * x + p.b, p.g) : p.c * x;
-}
-
-static constexpr float rcpFullResponse(float x, const ColorSpace::TransferParameters& p) {
- return x >= p.d * p.c ? (std::pow(x - p.e, 1.0f / p.g) - p.b) / p.a : (x - p.f) / p.c;
-}
-
-static constexpr float fullResponse(float x, const ColorSpace::TransferParameters& p) {
- return x >= p.d ? std::pow(p.a * x + p.b, p.g) + p.e : p.c * x + p.f;
-}
-
-static float absRcpResponse(float x, float g,float a, float b, float c, float d) {
- float xx = std::abs(x);
- return std::copysign(xx >= d * c ? (std::pow(xx, 1.0f / g) - b) / a : xx / c, x);
-}
-
-static float absResponse(float x, float g, float a, float b, float c, float d) {
- float xx = std::abs(x);
- return std::copysign(xx >= d ? std::pow(a * xx + b, g) : c * xx, x);
-}
-
-static float safePow(float x, float e) {
- return powf(x < 0.0f ? 0.0f : x, e);
-}
-
-static ColorSpace::transfer_function toOETF(const ColorSpace::TransferParameters& parameters) {
- if (parameters.e == 0.0f && parameters.f == 0.0f) {
- return std::bind(rcpResponse, _1, parameters);
- }
- return std::bind(rcpFullResponse, _1, parameters);
-}
-
-static ColorSpace::transfer_function toEOTF( const ColorSpace::TransferParameters& parameters) {
- if (parameters.e == 0.0f && parameters.f == 0.0f) {
- return std::bind(response, _1, parameters);
- }
- return std::bind(fullResponse, _1, parameters);
-}
-
-static ColorSpace::transfer_function toOETF(float gamma) {
- if (gamma == 1.0f) {
- return linearResponse;
- }
- return std::bind(safePow, _1, 1.0f / gamma);
-}
-
-static ColorSpace::transfer_function toEOTF(float gamma) {
- if (gamma == 1.0f) {
- return linearResponse;
- }
- return std::bind(safePow, _1, gamma);
-}
-
-static constexpr std::array<float2, 3> computePrimaries(const mat3& rgbToXYZ) {
- float3 r(rgbToXYZ * float3{1, 0, 0});
- float3 g(rgbToXYZ * float3{0, 1, 0});
- float3 b(rgbToXYZ * float3{0, 0, 1});
-
- return {{r.xy / dot(r, float3{1}),
- g.xy / dot(g, float3{1}),
- b.xy / dot(b, float3{1})}};
-}
-
-static constexpr float2 computeWhitePoint(const mat3& rgbToXYZ) {
- float3 w(rgbToXYZ * float3{1});
- return w.xy / dot(w, float3{1});
-}
-
-ColorSpace::ColorSpace(
- const std::string& name,
- const mat3& rgbToXYZ,
- transfer_function OETF,
- transfer_function EOTF,
- clamping_function clamper) noexcept
- : mName(name)
- , mRGBtoXYZ(rgbToXYZ)
- , mXYZtoRGB(inverse(rgbToXYZ))
- , mOETF(std::move(OETF))
- , mEOTF(std::move(EOTF))
- , mClamper(std::move(clamper))
- , mPrimaries(computePrimaries(rgbToXYZ))
- , mWhitePoint(computeWhitePoint(rgbToXYZ)) {
-}
-
-ColorSpace::ColorSpace(
- const std::string& name,
- const mat3& rgbToXYZ,
- const TransferParameters parameters,
- clamping_function clamper) noexcept
- : mName(name)
- , mRGBtoXYZ(rgbToXYZ)
- , mXYZtoRGB(inverse(rgbToXYZ))
- , mParameters(parameters)
- , mOETF(toOETF(mParameters))
- , mEOTF(toEOTF(mParameters))
- , mClamper(std::move(clamper))
- , mPrimaries(computePrimaries(rgbToXYZ))
- , mWhitePoint(computeWhitePoint(rgbToXYZ)) {
-}
-
-ColorSpace::ColorSpace(
- const std::string& name,
- const mat3& rgbToXYZ,
- float gamma,
- clamping_function clamper) noexcept
- : mName(name)
- , mRGBtoXYZ(rgbToXYZ)
- , mXYZtoRGB(inverse(rgbToXYZ))
- , mParameters({gamma, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f})
- , mOETF(toOETF(gamma))
- , mEOTF(toEOTF(gamma))
- , mClamper(std::move(clamper))
- , mPrimaries(computePrimaries(rgbToXYZ))
- , mWhitePoint(computeWhitePoint(rgbToXYZ)) {
-}
-
-ColorSpace::ColorSpace(
- const std::string& name,
- const std::array<float2, 3>& primaries,
- const float2& whitePoint,
- transfer_function OETF,
- transfer_function EOTF,
- clamping_function clamper) noexcept
- : mName(name)
- , mRGBtoXYZ(computeXYZMatrix(primaries, whitePoint))
- , mXYZtoRGB(inverse(mRGBtoXYZ))
- , mOETF(std::move(OETF))
- , mEOTF(std::move(EOTF))
- , mClamper(std::move(clamper))
- , mPrimaries(primaries)
- , mWhitePoint(whitePoint) {
-}
-
-ColorSpace::ColorSpace(
- const std::string& name,
- const std::array<float2, 3>& primaries,
- const float2& whitePoint,
- const TransferParameters parameters,
- clamping_function clamper) noexcept
- : mName(name)
- , mRGBtoXYZ(computeXYZMatrix(primaries, whitePoint))
- , mXYZtoRGB(inverse(mRGBtoXYZ))
- , mParameters(parameters)
- , mOETF(toOETF(mParameters))
- , mEOTF(toEOTF(mParameters))
- , mClamper(std::move(clamper))
- , mPrimaries(primaries)
- , mWhitePoint(whitePoint) {
-}
-
-ColorSpace::ColorSpace(
- const std::string& name,
- const std::array<float2, 3>& primaries,
- const float2& whitePoint,
- float gamma,
- clamping_function clamper) noexcept
- : mName(name)
- , mRGBtoXYZ(computeXYZMatrix(primaries, whitePoint))
- , mXYZtoRGB(inverse(mRGBtoXYZ))
- , mParameters({gamma, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f})
- , mOETF(toOETF(gamma))
- , mEOTF(toEOTF(gamma))
- , mClamper(std::move(clamper))
- , mPrimaries(primaries)
- , mWhitePoint(whitePoint) {
-}
-
-constexpr mat3 ColorSpace::computeXYZMatrix(
- const std::array<float2, 3>& primaries, const float2& whitePoint) {
- const float2& R = primaries[0];
- const float2& G = primaries[1];
- const float2& B = primaries[2];
- const float2& W = whitePoint;
-
- float oneRxRy = (1 - R.x) / R.y;
- float oneGxGy = (1 - G.x) / G.y;
- float oneBxBy = (1 - B.x) / B.y;
- float oneWxWy = (1 - W.x) / W.y;
-
- float RxRy = R.x / R.y;
- float GxGy = G.x / G.y;
- float BxBy = B.x / B.y;
- float WxWy = W.x / W.y;
-
- float BY =
- ((oneWxWy - oneRxRy) * (GxGy - RxRy) - (WxWy - RxRy) * (oneGxGy - oneRxRy)) /
- ((oneBxBy - oneRxRy) * (GxGy - RxRy) - (BxBy - RxRy) * (oneGxGy - oneRxRy));
- float GY = (WxWy - RxRy - BY * (BxBy - RxRy)) / (GxGy - RxRy);
- float RY = 1 - GY - BY;
-
- float RYRy = RY / R.y;
- float GYGy = GY / G.y;
- float BYBy = BY / B.y;
-
- return {
- float3{RYRy * R.x, RY, RYRy * (1 - R.x - R.y)},
- float3{GYGy * G.x, GY, GYGy * (1 - G.x - G.y)},
- float3{BYBy * B.x, BY, BYBy * (1 - B.x - B.y)}
- };
-}
-
-const ColorSpace ColorSpace::sRGB() {
- return {
- "sRGB IEC61966-2.1",
- {{float2{0.640f, 0.330f}, {0.300f, 0.600f}, {0.150f, 0.060f}}},
- {0.3127f, 0.3290f},
- {2.4f, 1 / 1.055f, 0.055f / 1.055f, 1 / 12.92f, 0.04045f, 0.0f, 0.0f}
- };
-}
-
-const ColorSpace ColorSpace::linearSRGB() {
- return {
- "sRGB IEC61966-2.1 (Linear)",
- {{float2{0.640f, 0.330f}, {0.300f, 0.600f}, {0.150f, 0.060f}}},
- {0.3127f, 0.3290f}
- };
-}
-
-const ColorSpace ColorSpace::extendedSRGB() {
- return {
- "scRGB-nl IEC 61966-2-2:2003",
- {{float2{0.640f, 0.330f}, {0.300f, 0.600f}, {0.150f, 0.060f}}},
- {0.3127f, 0.3290f},
- std::bind(absRcpResponse, _1, 2.4f, 1 / 1.055f, 0.055f / 1.055f, 1 / 12.92f, 0.04045f),
- std::bind(absResponse, _1, 2.4f, 1 / 1.055f, 0.055f / 1.055f, 1 / 12.92f, 0.04045f),
- std::bind(clamp<float>, _1, -0.799f, 2.399f)
- };
-}
-
-const ColorSpace ColorSpace::linearExtendedSRGB() {
- return {
- "scRGB IEC 61966-2-2:2003",
- {{float2{0.640f, 0.330f}, {0.300f, 0.600f}, {0.150f, 0.060f}}},
- {0.3127f, 0.3290f},
- 1.0f,
- std::bind(clamp<float>, _1, -0.5f, 7.499f)
- };
-}
-
-const ColorSpace ColorSpace::NTSC() {
- return {
- "NTSC (1953)",
- {{float2{0.67f, 0.33f}, {0.21f, 0.71f}, {0.14f, 0.08f}}},
- {0.310f, 0.316f},
- {1 / 0.45f, 1 / 1.099f, 0.099f / 1.099f, 1 / 4.5f, 0.081f, 0.0f, 0.0f}
- };
-}
-
-const ColorSpace ColorSpace::BT709() {
- return {
- "Rec. ITU-R BT.709-5",
- {{float2{0.640f, 0.330f}, {0.300f, 0.600f}, {0.150f, 0.060f}}},
- {0.3127f, 0.3290f},
- {1 / 0.45f, 1 / 1.099f, 0.099f / 1.099f, 1 / 4.5f, 0.081f, 0.0f, 0.0f}
- };
-}
-
-const ColorSpace ColorSpace::BT2020() {
- return {
- "Rec. ITU-R BT.2020-1",
- {{float2{0.708f, 0.292f}, {0.170f, 0.797f}, {0.131f, 0.046f}}},
- {0.3127f, 0.3290f},
- {1 / 0.45f, 1 / 1.099f, 0.099f / 1.099f, 1 / 4.5f, 0.081f, 0.0f, 0.0f}
- };
-}
-
-const ColorSpace ColorSpace::AdobeRGB() {
- return {
- "Adobe RGB (1998)",
- {{float2{0.64f, 0.33f}, {0.21f, 0.71f}, {0.15f, 0.06f}}},
- {0.3127f, 0.3290f},
- 2.2f
- };
-}
-
-const ColorSpace ColorSpace::ProPhotoRGB() {
- return {
- "ROMM RGB ISO 22028-2:2013",
- {{float2{0.7347f, 0.2653f}, {0.1596f, 0.8404f}, {0.0366f, 0.0001f}}},
- {0.34567f, 0.35850f},
- {1.8f, 1.0f, 0.0f, 1 / 16.0f, 0.031248f, 0.0f, 0.0f}
- };
-}
-
-const ColorSpace ColorSpace::DisplayP3() {
- return {
- "Display P3",
- {{float2{0.680f, 0.320f}, {0.265f, 0.690f}, {0.150f, 0.060f}}},
- {0.3127f, 0.3290f},
- {2.4f, 1 / 1.055f, 0.055f / 1.055f, 1 / 12.92f, 0.039f, 0.0f, 0.0f}
- };
-}
-
-const ColorSpace ColorSpace::DCIP3() {
- return {
- "SMPTE RP 431-2-2007 DCI (P3)",
- {{float2{0.680f, 0.320f}, {0.265f, 0.690f}, {0.150f, 0.060f}}},
- {0.314f, 0.351f},
- 2.6f
- };
-}
-
-const ColorSpace ColorSpace::ACES() {
- return {
- "SMPTE ST 2065-1:2012 ACES",
- {{float2{0.73470f, 0.26530f}, {0.0f, 1.0f}, {0.00010f, -0.0770f}}},
- {0.32168f, 0.33767f},
- 1.0f,
- std::bind(clamp<float>, _1, -65504.0f, 65504.0f)
- };
-}
-
-const ColorSpace ColorSpace::ACEScg() {
- return {
- "Academy S-2014-004 ACEScg",
- {{float2{0.713f, 0.293f}, {0.165f, 0.830f}, {0.128f, 0.044f}}},
- {0.32168f, 0.33767f},
- 1.0f,
- std::bind(clamp<float>, _1, -65504.0f, 65504.0f)
- };
-}
-
-std::unique_ptr<float3[]> ColorSpace::createLUT(uint32_t size, const ColorSpace& src,
- const ColorSpace& dst) {
- size = clamp(size, 2u, 256u);
- float m = 1.0f / float(size - 1);
-
- std::unique_ptr<float3[]> lut(new float3[size * size * size]);
- float3* data = lut.get();
-
- ColorSpaceConnector connector(src, dst);
-
- for (uint32_t z = 0; z < size; z++) {
- for (int32_t y = int32_t(size - 1); y >= 0; y--) {
- for (uint32_t x = 0; x < size; x++) {
- *data++ = connector.transform({x * m, y * m, z * m});
- }
- }
- }
-
- return lut;
-}
-
-static const float2 ILLUMINANT_D50_XY = {0.34567f, 0.35850f};
-static const float3 ILLUMINANT_D50_XYZ = {0.964212f, 1.0f, 0.825188f};
-static const mat3 BRADFORD = mat3{
- float3{ 0.8951f, -0.7502f, 0.0389f},
- float3{ 0.2664f, 1.7135f, -0.0685f},
- float3{-0.1614f, 0.0367f, 1.0296f}
-};
-
-static mat3 adaptation(const mat3& matrix, const float3& srcWhitePoint, const float3& dstWhitePoint) {
- float3 srcLMS = matrix * srcWhitePoint;
- float3 dstLMS = matrix * dstWhitePoint;
- return inverse(matrix) * mat3{dstLMS / srcLMS} * matrix;
-}
-
-ColorSpaceConnector::ColorSpaceConnector(
- const ColorSpace& src,
- const ColorSpace& dst) noexcept
- : mSource(src)
- , mDestination(dst) {
-
- if (all(lessThan(abs(src.getWhitePoint() - dst.getWhitePoint()), float2{1e-3f}))) {
- mTransform = dst.getXYZtoRGB() * src.getRGBtoXYZ();
- } else {
- mat3 rgbToXYZ(src.getRGBtoXYZ());
- mat3 xyzToRGB(dst.getXYZtoRGB());
-
- float3 srcXYZ = ColorSpace::XYZ(float3{src.getWhitePoint(), 1});
- float3 dstXYZ = ColorSpace::XYZ(float3{dst.getWhitePoint(), 1});
-
- if (any(greaterThan(abs(src.getWhitePoint() - ILLUMINANT_D50_XY), float2{1e-3f}))) {
- rgbToXYZ = adaptation(BRADFORD, srcXYZ, ILLUMINANT_D50_XYZ) * src.getRGBtoXYZ();
- }
-
- if (any(greaterThan(abs(dst.getWhitePoint() - ILLUMINANT_D50_XY), float2{1e-3f}))) {
- xyzToRGB = inverse(adaptation(BRADFORD, dstXYZ, ILLUMINANT_D50_XYZ) * dst.getRGBtoXYZ());
- }
-
- mTransform = xyzToRGB * rgbToXYZ;
- }
-}
-
-}; // namespace android
diff --git a/location/java/android/location/altitude/AltitudeConverter.java b/location/java/android/location/altitude/AltitudeConverter.java
index 3dc024ef..6f88912 100644
--- a/location/java/android/location/altitude/AltitudeConverter.java
+++ b/location/java/android/location/altitude/AltitudeConverter.java
@@ -19,9 +19,11 @@
import android.annotation.NonNull;
import android.annotation.WorkerThread;
import android.content.Context;
+import android.frameworks.location.altitude.GetGeoidHeightRequest;
+import android.frameworks.location.altitude.GetGeoidHeightResponse;
import android.location.Location;
-import com.android.internal.location.altitude.GeoidHeightMap;
+import com.android.internal.location.altitude.GeoidMap;
import com.android.internal.location.altitude.S2CellIdUtils;
import com.android.internal.location.altitude.nano.MapParamsProto;
import com.android.internal.util.Preconditions;
@@ -37,7 +39,7 @@
* <pre>
* Brian Julian and Michael Angermann.
* "Resource efficient and accurate altitude conversion to Mean Sea Level."
- * To appear in 2023 IEEE/ION Position, Location and Navigation Symposium (PLANS).
+ * 2023 IEEE/ION Position, Location and Navigation Symposium (PLANS).
* </pre>
*/
public final class AltitudeConverter {
@@ -45,8 +47,8 @@
private static final double MAX_ABS_VALID_LATITUDE = 90;
private static final double MAX_ABS_VALID_LONGITUDE = 180;
- /** Manages a mapping of geoid heights associated with S2 cells. */
- private final GeoidHeightMap mGeoidHeightMap = new GeoidHeightMap();
+ /** Manages a mapping of geoid heights and expiration distances associated with S2 cells. */
+ private final GeoidMap mGeoidMap = new GeoidMap();
/**
* Creates an instance that manages an independent cache to optimized conversions of locations
@@ -78,75 +80,87 @@
/**
* Returns the four S2 cell IDs for the map square associated with the {@code location}.
*
- * <p>The first map cell contains the location, while the others are located horizontally,
- * vertically, and diagonally, in that order, with respect to the S2 (i,j) coordinate system. If
- * the diagonal map cell does not exist (i.e., the location is near an S2 cube vertex), its
- * corresponding ID is set to zero.
+ * <p>The first map cell, denoted z11 in the appendix of the referenced paper above, contains
+ * the location. The others are the map cells denoted z21, z12, and z22, in that order.
*/
- @NonNull
- private static long[] findMapSquare(@NonNull MapParamsProto params,
+ private static long[] findMapSquare(@NonNull MapParamsProto geoidHeightParams,
@NonNull Location location) {
long s2CellId = S2CellIdUtils.fromLatLngDegrees(location.getLatitude(),
location.getLongitude());
// Cell-space properties and coordinates.
- int sizeIj = 1 << (S2CellIdUtils.MAX_LEVEL - params.mapS2Level);
+ int sizeIj = 1 << (S2CellIdUtils.MAX_LEVEL - geoidHeightParams.mapS2Level);
int maxIj = 1 << S2CellIdUtils.MAX_LEVEL;
- long s0 = S2CellIdUtils.getParent(s2CellId, params.mapS2Level);
- int f0 = S2CellIdUtils.getFace(s2CellId);
- int i0 = S2CellIdUtils.getI(s2CellId);
- int j0 = S2CellIdUtils.getJ(s2CellId);
- int i1 = i0 + sizeIj;
- int j1 = j0 + sizeIj;
+ long z11 = S2CellIdUtils.getParent(s2CellId, geoidHeightParams.mapS2Level);
+ int f11 = S2CellIdUtils.getFace(s2CellId);
+ int i1 = S2CellIdUtils.getI(s2CellId);
+ int j1 = S2CellIdUtils.getJ(s2CellId);
+ int i2 = i1 + sizeIj;
+ int j2 = j1 + sizeIj;
// Non-boundary region calculation - simplest and most common case.
- if (i1 < maxIj && j1 < maxIj) {
- return new long[]{
- s0,
- S2CellIdUtils.getParent(S2CellIdUtils.fromFij(f0, i1, j0), params.mapS2Level),
- S2CellIdUtils.getParent(S2CellIdUtils.fromFij(f0, i0, j1), params.mapS2Level),
- S2CellIdUtils.getParent(S2CellIdUtils.fromFij(f0, i1, j1), params.mapS2Level)
- };
+ if (i2 < maxIj && j2 < maxIj) {
+ return new long[]{z11, S2CellIdUtils.getParent(S2CellIdUtils.fromFij(f11, i2, j1),
+ geoidHeightParams.mapS2Level), S2CellIdUtils.getParent(
+ S2CellIdUtils.fromFij(f11, i1, j2), geoidHeightParams.mapS2Level),
+ S2CellIdUtils.getParent(S2CellIdUtils.fromFij(f11, i2, j2),
+ geoidHeightParams.mapS2Level)};
}
- // Boundary region calculation.
+ // Boundary region calculation
long[] edgeNeighbors = new long[4];
- S2CellIdUtils.getEdgeNeighbors(s0, edgeNeighbors);
- long s1 = edgeNeighbors[1];
- long s2 = edgeNeighbors[2];
- long s3;
- if (f0 % 2 == 1) {
- S2CellIdUtils.getEdgeNeighbors(s1, edgeNeighbors);
- if (i1 < maxIj) {
- s3 = edgeNeighbors[2];
- } else {
- s3 = s1;
- s1 = edgeNeighbors[1];
- }
- } else {
- S2CellIdUtils.getEdgeNeighbors(s2, edgeNeighbors);
- if (j1 < maxIj) {
- s3 = edgeNeighbors[1];
- } else {
- s3 = s2;
- s2 = edgeNeighbors[3];
- }
- }
+ S2CellIdUtils.getEdgeNeighbors(z11, edgeNeighbors);
+ long z11W = edgeNeighbors[0];
+ long z11S = edgeNeighbors[1];
+ long z11E = edgeNeighbors[2];
+ long z11N = edgeNeighbors[3];
+
+ long[] otherEdgeNeighbors = new long[4];
+ S2CellIdUtils.getEdgeNeighbors(z11W, otherEdgeNeighbors);
+ S2CellIdUtils.getEdgeNeighbors(z11S, edgeNeighbors);
+ long z11Sw = findCommonNeighbor(edgeNeighbors, otherEdgeNeighbors, z11);
+ S2CellIdUtils.getEdgeNeighbors(z11E, otherEdgeNeighbors);
+ long z11Se = findCommonNeighbor(edgeNeighbors, otherEdgeNeighbors, z11);
+ S2CellIdUtils.getEdgeNeighbors(z11N, edgeNeighbors);
+ long z11Ne = findCommonNeighbor(edgeNeighbors, otherEdgeNeighbors, z11);
+
+ long z21 = (f11 % 2 == 1 && i2 >= maxIj) ? z11Sw : z11S;
+ long z12 = (f11 % 2 == 0 && j2 >= maxIj) ? z11Ne : z11E;
+ long z22 = (z21 == z11Sw) ? z11S : (z12 == z11Ne) ? z11E : z11Se;
// Reuse edge neighbors' array to avoid an extra allocation.
- edgeNeighbors[0] = s0;
- edgeNeighbors[1] = s1;
- edgeNeighbors[2] = s2;
- edgeNeighbors[3] = s3;
+ edgeNeighbors[0] = z11;
+ edgeNeighbors[1] = z21;
+ edgeNeighbors[2] = z12;
+ edgeNeighbors[3] = z22;
return edgeNeighbors;
}
/**
+ * Returns the first common non-z11 neighbor found between the two arrays of edge neighbors. If
+ * such a common neighbor does not exist, returns z11.
+ */
+ private static long findCommonNeighbor(long[] edgeNeighbors, long[] otherEdgeNeighbors,
+ long z11) {
+ for (long edgeNeighbor : edgeNeighbors) {
+ if (edgeNeighbor == z11) {
+ continue;
+ }
+ for (long otherEdgeNeighbor : otherEdgeNeighbors) {
+ if (edgeNeighbor == otherEdgeNeighbor) {
+ return edgeNeighbor;
+ }
+ }
+ }
+ return z11;
+ }
+
+ /**
* Adds to {@code location} the bilinearly interpolated Mean Sea Level altitude. In addition, a
* Mean Sea Level altitude accuracy is added if the {@code location} has a valid vertical
* accuracy; otherwise, does not add a corresponding accuracy.
*/
- private static void addMslAltitude(@NonNull MapParamsProto params,
+ private static void addMslAltitude(@NonNull MapParamsProto geoidHeightParams,
@NonNull double[] geoidHeightsMeters, @NonNull Location location) {
double h0 = geoidHeightsMeters[0];
double h1 = geoidHeightsMeters[1];
@@ -158,7 +172,7 @@
// employ the simplified unit square formulation.
long s2CellId = S2CellIdUtils.fromLatLngDegrees(location.getLatitude(),
location.getLongitude());
- double sizeIj = 1 << (S2CellIdUtils.MAX_LEVEL - params.mapS2Level);
+ double sizeIj = 1 << (S2CellIdUtils.MAX_LEVEL - geoidHeightParams.mapS2Level);
double wi = (S2CellIdUtils.getI(s2CellId) % sizeIj) / sizeIj;
double wj = (S2CellIdUtils.getJ(s2CellId) % sizeIj) / sizeIj;
double offsetMeters = h0 + (h1 - h0) * wi + (h2 - h0) * wj + (h3 - h1 - h2 + h0) * wi * wj;
@@ -167,8 +181,8 @@
if (location.hasVerticalAccuracy()) {
double verticalAccuracyMeters = location.getVerticalAccuracyMeters();
if (Double.isFinite(verticalAccuracyMeters) && verticalAccuracyMeters >= 0) {
- location.setMslAltitudeAccuracyMeters(
- (float) Math.hypot(verticalAccuracyMeters, params.modelRmseMeters));
+ location.setMslAltitudeAccuracyMeters((float) Math.hypot(verticalAccuracyMeters,
+ geoidHeightParams.modelRmseMeters));
}
}
}
@@ -191,10 +205,11 @@
public void addMslAltitudeToLocation(@NonNull Context context, @NonNull Location location)
throws IOException {
validate(location);
- MapParamsProto params = GeoidHeightMap.getParams(context);
- long[] s2CellIds = findMapSquare(params, location);
- double[] geoidHeightsMeters = mGeoidHeightMap.readGeoidHeights(params, context, s2CellIds);
- addMslAltitude(params, geoidHeightsMeters, location);
+ MapParamsProto geoidHeightParams = GeoidMap.getGeoidHeightParams(context);
+ long[] mapCells = findMapSquare(geoidHeightParams, location);
+ double[] geoidHeightsMeters = mGeoidMap.readGeoidHeights(geoidHeightParams, context,
+ mapCells);
+ addMslAltitude(geoidHeightParams, geoidHeightsMeters, location);
}
/**
@@ -206,18 +221,68 @@
*/
public boolean addMslAltitudeToLocation(@NonNull Location location) {
validate(location);
- MapParamsProto params = GeoidHeightMap.getParams();
- if (params == null) {
+ MapParamsProto geoidHeightParams = GeoidMap.getGeoidHeightParams();
+ if (geoidHeightParams == null) {
return false;
}
- long[] s2CellIds = findMapSquare(params, location);
- double[] geoidHeightsMeters = mGeoidHeightMap.readGeoidHeights(params, s2CellIds);
+ long[] mapCells = findMapSquare(geoidHeightParams, location);
+ double[] geoidHeightsMeters = mGeoidMap.readGeoidHeights(geoidHeightParams, mapCells);
if (geoidHeightsMeters == null) {
return false;
}
- addMslAltitude(params, geoidHeightsMeters, location);
+ addMslAltitude(geoidHeightParams, geoidHeightsMeters, location);
return true;
}
+
+ /**
+ * Returns the geoid height (a.k.a. geoid undulation) at the location specified in {@code
+ * request}. The geoid height at a location is defined as the difference between an altitude
+ * measured above the World Geodetic System 1984 reference ellipsoid (WGS84) and its
+ * corresponding Mean Sea Level altitude.
+ *
+ * <p>Must be called off the main thread as data may be loaded from raw assets.
+ *
+ * @throws IOException if an I/O error occurs when loading data from raw assets.
+ * @throws IllegalArgumentException if the {@code request} has an invalid latitude or longitude.
+ * Specifically, the latitude must be between -90 and 90 (both
+ * inclusive), and the longitude must be between -180 and 180
+ * (both inclusive).
+ * @hide
+ */
+ @WorkerThread
+ public @NonNull GetGeoidHeightResponse getGeoidHeight(@NonNull Context context,
+ @NonNull GetGeoidHeightRequest request) throws IOException {
+ // Create a valid location from which the geoid height and its accuracy will be extracted.
+ Location location = new Location("");
+ location.setLatitude(request.latitudeDegrees);
+ location.setLongitude(request.longitudeDegrees);
+ location.setAltitude(0.0);
+ location.setVerticalAccuracyMeters(0.0f);
+
+ addMslAltitudeToLocation(context, location);
+ // The geoid height for a location with zero WGS84 altitude is equal in value to the
+ // negative of corresponding MSL altitude.
+ double geoidHeightMeters = -location.getMslAltitudeMeters();
+ // The geoid height error for a location with zero vertical accuracy is equal in value to
+ // the corresponding MSL altitude accuracy.
+ float geoidHeightErrorMeters = location.getMslAltitudeAccuracyMeters();
+
+ MapParamsProto expirationDistanceParams = GeoidMap.getExpirationDistanceParams(context);
+ long s2CellId = S2CellIdUtils.fromLatLngDegrees(location.getLatitude(),
+ location.getLongitude());
+ long[] mapCell = {S2CellIdUtils.getParent(s2CellId, expirationDistanceParams.mapS2Level)};
+ double expirationDistanceMeters = mGeoidMap.readExpirationDistances(
+ expirationDistanceParams, context, mapCell)[0];
+ float additionalGeoidHeightErrorMeters = (float) expirationDistanceParams.modelRmseMeters;
+
+ GetGeoidHeightResponse response = new GetGeoidHeightResponse();
+ response.geoidHeightMeters = geoidHeightMeters;
+ response.geoidHeightErrorMeters = geoidHeightErrorMeters;
+ response.expirationDistanceMeters = expirationDistanceMeters;
+ response.additionalGeoidHeightErrorMeters = additionalGeoidHeightErrorMeters;
+ response.success = true;
+ return response;
+ }
}
diff --git a/location/java/android/location/flags/gnss.aconfig b/location/java/android/location/flags/location.aconfig
similarity index 88%
rename from location/java/android/location/flags/gnss.aconfig
rename to location/java/android/location/flags/location.aconfig
index 8c7c871..32ad09c 100644
--- a/location/java/android/location/flags/gnss.aconfig
+++ b/location/java/android/location/flags/location.aconfig
@@ -1,6 +1,13 @@
package: "android.location.flags"
flag {
+ name: "fix_service_watcher"
+ namespace: "location"
+ description: "Enable null explicit services in ServiceWatcher"
+ bug: "311210517"
+}
+
+flag {
name: "gnss_api_navic_l1"
namespace: "location"
description: "Flag for GNSS API for NavIC L1"
diff --git a/location/java/com/android/internal/location/altitude/GeoidHeightMap.java b/location/java/com/android/internal/location/altitude/GeoidMap.java
similarity index 65%
rename from location/java/com/android/internal/location/altitude/GeoidHeightMap.java
rename to location/java/com/android/internal/location/altitude/GeoidMap.java
index 8067050..9bf5689 100644
--- a/location/java/com/android/internal/location/altitude/GeoidHeightMap.java
+++ b/location/java/com/android/internal/location/altitude/GeoidMap.java
@@ -34,11 +34,12 @@
import java.util.Objects;
/**
- * Manages a mapping of geoid heights associated with S2 cells, referred to as MAP CELLS.
+ * Manages a mapping of geoid heights and expiration distances associated with S2 cells, referred to
+ * as MAP CELLS.
*
* <p>Tiles are used extensively to reduce the number of entries needed to be stored in memory and
- * on disk. A tile associates geoid heights with all map cells of a common parent at a specified S2
- * level.
+ * on disk. A tile associates geoid heights or expiration distances with all map cells of a common
+ * parent at a specified S2 level.
*
* <p>Since bilinear interpolation considers at most four map cells at a time, at most four tiles
* are simultaneously stored in memory. These tiles, referred to as CACHE TILES, are each keyed by
@@ -48,42 +49,79 @@
* The latter tiles, referred to as DISK TILES, are each keyed by its common parent's S2 cell token,
* referred to as a DISK TOKEN.
*/
-public final class GeoidHeightMap {
+public final class GeoidMap {
- private static final Object sLock = new Object();
+ private static final Object GEOID_HEIGHT_PARAMS_LOCK = new Object();
- @GuardedBy("sLock")
+ private static final Object EXPIRATION_DISTANCE_PARAMS_LOCK = new Object();
+
+ @GuardedBy("GEOID_HEIGHT_PARAMS_LOCK")
@Nullable
- private static MapParamsProto sParams;
+ private static MapParamsProto sGeoidHeightParams;
- /** Defines a cache large enough to hold all cache tiles needed for interpolation. */
- private final LruCache<Long, S2TileProto> mCacheTiles = new LruCache<>(4);
+ @GuardedBy("EXPIRATION_DISTANCE_PARAMS_LOCK")
+ @Nullable
+ private static MapParamsProto sExpirationDistanceParams;
/**
- * Returns the singleton parameter instance for a spherically projected geoid height map and its
- * corresponding tile management.
+ * Defines a cache large enough to hold all geoid height cache tiles needed for interpolation.
+ */
+ private final LruCache<Long, S2TileProto> mGeoidHeightCacheTiles = new LruCache<>(4);
+
+ /**
+ * Defines a cache large enough to hold all expiration distance cache tiles needed for
+ * interpolation.
+ */
+ private final LruCache<Long, S2TileProto> mExpirationDistanceCacheTiles = new LruCache<>(4);
+
+ /**
+ * Returns the singleton parameter instance for geoid height parameters of a spherically
+ * projected map.
*/
@NonNull
- public static MapParamsProto getParams(@NonNull Context context) throws IOException {
- synchronized (sLock) {
- if (sParams == null) {
- try (InputStream is = context.getApplicationContext().getAssets().open(
- "geoid_height_map/map-params.pb")) {
- sParams = MapParamsProto.parseFrom(is.readAllBytes());
- }
+ public static MapParamsProto getGeoidHeightParams(@NonNull Context context) throws IOException {
+ synchronized (GEOID_HEIGHT_PARAMS_LOCK) {
+ if (sGeoidHeightParams == null) {
+ // TODO: b/304375846 - Configure with disk tile prefix once resources are updated.
+ sGeoidHeightParams = parseParams(context);
}
- return sParams;
+ return sGeoidHeightParams;
}
}
/**
- * Same as {@link #getParams(Context)} except that null is returned if the singleton parameter
- * instance is not yet initialized.
+ * Returns the singleton parameter instance for expiration distance parameters of a spherically
+ * projected
+ * map.
+ */
+ @NonNull
+ public static MapParamsProto getExpirationDistanceParams(@NonNull Context context)
+ throws IOException {
+ synchronized (EXPIRATION_DISTANCE_PARAMS_LOCK) {
+ if (sExpirationDistanceParams == null) {
+ // TODO: b/304375846 - Configure with disk tile prefix once resources are updated.
+ sExpirationDistanceParams = parseParams(context);
+ }
+ return sExpirationDistanceParams;
+ }
+ }
+
+ @NonNull
+ private static MapParamsProto parseParams(@NonNull Context context) throws IOException {
+ try (InputStream is = context.getApplicationContext().getAssets().open(
+ "geoid_height_map/map-params.pb")) {
+ return MapParamsProto.parseFrom(is.readAllBytes());
+ }
+ }
+
+ /**
+ * Same as {@link #getGeoidHeightParams(Context)} except that null is returned if the singleton
+ * parameter instance is not yet initialized.
*/
@Nullable
- public static MapParamsProto getParams() {
- synchronized (sLock) {
- return sParams;
+ public static MapParamsProto getGeoidHeightParams() {
+ synchronized (GEOID_HEIGHT_PARAMS_LOCK) {
+ return sGeoidHeightParams;
}
}
@@ -93,18 +131,17 @@
@NonNull
private static String getDiskToken(@NonNull MapParamsProto params, long s2CellId) {
- return S2CellIdUtils.getToken(
- S2CellIdUtils.getParent(s2CellId, params.diskTileS2Level));
+ return S2CellIdUtils.getToken(S2CellIdUtils.getParent(s2CellId, params.diskTileS2Level));
}
/**
* Adds to {@code values} values in the unit interval [0, 1] for the map cells identified by
- * {@code s2CellIds}. Returns true if values are present for all IDs; otherwise, returns false
- * and adds NaNs for absent values.
+ * {@code s2CellIds}. Returns true if values are present for all IDs; otherwise, adds NaNs for
+ * absent values and returns false.
*/
private static boolean getUnitIntervalValues(@NonNull MapParamsProto params,
- @NonNull TileFunction tileFunction,
- @NonNull long[] s2CellIds, @NonNull double[] values) {
+ @NonNull TileFunction tileFunction, @NonNull long[] s2CellIds,
+ @NonNull double[] values) {
int len = s2CellIds.length;
S2TileProto[] tiles = new S2TileProto[len];
@@ -137,9 +174,8 @@
@SuppressWarnings("ReferenceEquality")
private static void mergeByteBufferValues(@NonNull MapParamsProto params,
- @NonNull long[] s2CellIds,
- @NonNull S2TileProto[] tiles,
- int tileIndex, @NonNull double[] values) {
+ @NonNull long[] s2CellIds, @NonNull S2TileProto[] tiles, int tileIndex,
+ @NonNull double[] values) {
byte[] bytes = tiles[tileIndex].byteBuffer;
if (bytes == null || bytes.length == 0) {
return;
@@ -163,24 +199,22 @@
}
private static void mergeByteJpegValues(@NonNull MapParamsProto params,
- @NonNull long[] s2CellIds,
- @NonNull S2TileProto[] tiles,
- int tileIndex, @NonNull double[] values) {
+ @NonNull long[] s2CellIds, @NonNull S2TileProto[] tiles, int tileIndex,
+ @NonNull double[] values) {
mergeByteImageValues(params, tiles[tileIndex].byteJpeg, s2CellIds, tiles, tileIndex,
values);
}
private static void mergeBytePngValues(@NonNull MapParamsProto params,
- @NonNull long[] s2CellIds,
- @NonNull S2TileProto[] tiles,
- int tileIndex, @NonNull double[] values) {
+ @NonNull long[] s2CellIds, @NonNull S2TileProto[] tiles, int tileIndex,
+ @NonNull double[] values) {
mergeByteImageValues(params, tiles[tileIndex].bytePng, s2CellIds, tiles, tileIndex, values);
}
@SuppressWarnings("ReferenceEquality")
private static void mergeByteImageValues(@NonNull MapParamsProto params, @NonNull byte[] bytes,
- @NonNull long[] s2CellIds,
- @NonNull S2TileProto[] tiles, int tileIndex, @NonNull double[] values) {
+ @NonNull long[] s2CellIds, @NonNull S2TileProto[] tiles, int tileIndex,
+ @NonNull double[] values) {
if (bytes == null || bytes.length == 0) {
return;
}
@@ -219,7 +253,7 @@
* ID.
*/
private static void validate(@NonNull MapParamsProto params, @NonNull long[] s2CellIds) {
- Preconditions.checkArgument(s2CellIds.length == 4);
+ Preconditions.checkArgument(s2CellIds.length <= 4);
for (long s2CellId : s2CellIds) {
Preconditions.checkArgument(S2CellIdUtils.getLevel(s2CellId) == params.mapS2Level);
}
@@ -233,15 +267,38 @@
@NonNull
public double[] readGeoidHeights(@NonNull MapParamsProto params, @NonNull Context context,
@NonNull long[] s2CellIds) throws IOException {
+ return readMapValues(params, context, s2CellIds, mGeoidHeightCacheTiles);
+ }
+
+ /**
+ * Returns the expiration distances in meters associated with the map cells identified by
+ * {@code s2CellIds}. Throws an {@link IOException} if a geoid height cannot be calculated for
+ * an ID.
+ */
+ @NonNull
+ public double[] readExpirationDistances(@NonNull MapParamsProto params,
+ @NonNull Context context, @NonNull long[] s2CellIds) throws IOException {
+ return readMapValues(params, context, s2CellIds, mExpirationDistanceCacheTiles);
+ }
+
+ /**
+ * Returns the map values in meters associated with the map cells identified by
+ * {@code s2CellIds}. Throws an {@link IOException} if a map value cannot be calculated for an
+ * ID.
+ */
+ @NonNull
+ private static double[] readMapValues(@NonNull MapParamsProto params, @NonNull Context context,
+ @NonNull long[] s2CellIds, @NonNull LruCache<Long, S2TileProto> cacheTiles)
+ throws IOException {
validate(params, s2CellIds);
- double[] heightsMeters = new double[s2CellIds.length];
- if (getGeoidHeights(params, mCacheTiles::get, s2CellIds, heightsMeters)) {
- return heightsMeters;
+ double[] mapValuesMeters = new double[s2CellIds.length];
+ if (getMapValues(params, cacheTiles::get, s2CellIds, mapValuesMeters)) {
+ return mapValuesMeters;
}
- TileFunction loadedTiles = loadFromCacheAndDisk(params, context, s2CellIds);
- if (getGeoidHeights(params, loadedTiles, s2CellIds, heightsMeters)) {
- return heightsMeters;
+ TileFunction loadedTiles = loadFromCacheAndDisk(params, context, s2CellIds, cacheTiles);
+ if (getMapValues(params, loadedTiles, s2CellIds, mapValuesMeters)) {
+ return mapValuesMeters;
}
throw new IOException("Unable to calculate geoid heights from raw assets.");
}
@@ -255,32 +312,33 @@
public double[] readGeoidHeights(@NonNull MapParamsProto params, @NonNull long[] s2CellIds) {
validate(params, s2CellIds);
double[] heightsMeters = new double[s2CellIds.length];
- if (getGeoidHeights(params, mCacheTiles::get, s2CellIds, heightsMeters)) {
+ if (getMapValues(params, mGeoidHeightCacheTiles::get, s2CellIds, heightsMeters)) {
return heightsMeters;
}
return null;
}
/**
- * Adds to {@code heightsMeters} the geoid heights in meters associated with the map cells
+ * Adds to {@code mapValuesMeters} the map values in meters associated with the map cells
* identified by {@code s2CellIds}. Returns true if heights are present for all IDs; otherwise,
- * returns false and adds NaNs for absent heights.
+ * adds NaNs for absent heights and returns false.
*/
- private boolean getGeoidHeights(@NonNull MapParamsProto params,
+ private static boolean getMapValues(@NonNull MapParamsProto params,
@NonNull TileFunction tileFunction, @NonNull long[] s2CellIds,
- @NonNull double[] heightsMeters) {
- boolean allFound = getUnitIntervalValues(params, tileFunction, s2CellIds, heightsMeters);
- for (int i = 0; i < heightsMeters.length; i++) {
+ @NonNull double[] mapValuesMeters) {
+ boolean allFound = getUnitIntervalValues(params, tileFunction, s2CellIds, mapValuesMeters);
+ for (int i = 0; i < mapValuesMeters.length; i++) {
// NaNs are properly preserved.
- heightsMeters[i] *= params.modelAMeters;
- heightsMeters[i] += params.modelBMeters;
+ mapValuesMeters[i] *= params.modelAMeters;
+ mapValuesMeters[i] += params.modelBMeters;
}
return allFound;
}
@NonNull
- private TileFunction loadFromCacheAndDisk(@NonNull MapParamsProto params,
- @NonNull Context context, @NonNull long[] s2CellIds) throws IOException {
+ private static TileFunction loadFromCacheAndDisk(@NonNull MapParamsProto params,
+ @NonNull Context context, @NonNull long[] s2CellIds,
+ @NonNull LruCache<Long, S2TileProto> cacheTiles) throws IOException {
int len = s2CellIds.length;
// Enable batch loading by finding all cache keys upfront.
@@ -296,7 +354,7 @@
if (diskTokens[i] != null) {
continue;
}
- loadedTiles[i] = mCacheTiles.get(cacheKeys[i]);
+ loadedTiles[i] = cacheTiles.get(cacheKeys[i]);
diskTokens[i] = getDiskToken(params, cacheKeys[i]);
// Batch across common cache key.
@@ -319,7 +377,7 @@
"geoid_height_map/tile-" + diskTokens[i] + ".pb")) {
tile = S2TileProto.parseFrom(is.readAllBytes());
}
- mergeFromDiskTile(params, tile, cacheKeys, diskTokens, i, loadedTiles);
+ mergeFromDiskTile(params, tile, cacheKeys, diskTokens, i, loadedTiles, cacheTiles);
}
return cacheKey -> {
@@ -332,9 +390,10 @@
};
}
- private void mergeFromDiskTile(@NonNull MapParamsProto params, @NonNull S2TileProto diskTile,
- @NonNull long[] cacheKeys, @NonNull String[] diskTokens, int diskTokenIndex,
- @NonNull S2TileProto[] loadedTiles) throws IOException {
+ private static void mergeFromDiskTile(@NonNull MapParamsProto params,
+ @NonNull S2TileProto diskTile, @NonNull long[] cacheKeys, @NonNull String[] diskTokens,
+ int diskTokenIndex, @NonNull S2TileProto[] loadedTiles,
+ @NonNull LruCache<Long, S2TileProto> cacheTiles) throws IOException {
int len = cacheKeys.length;
int numMapCellsPerCacheTile = 1 << (2 * (params.mapS2Level - params.cacheTileS2Level));
@@ -375,7 +434,7 @@
}
// Side load into tile cache.
- mCacheTiles.put(cacheKeys[i], loadedTiles[i]);
+ cacheTiles.put(cacheKeys[i], loadedTiles[i]);
}
}
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index 470a8ac..bfb4b42 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -17,6 +17,7 @@
package android.media;
import android.Manifest;
+import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -43,21 +44,25 @@
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.ReadOnlyBufferException;
+import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.BitSet;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
+import java.util.Optional;
import java.util.Set;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
+import static com.android.media.codec.flags.Flags.FLAG_LARGE_AUDIO_FRAME;
/**
MediaCodec class can be used to access low-level media codecs, i.e. encoder/decoder components.
It is part of the Android low-level multimedia support infrastructure (normally used together
@@ -1824,6 +1829,7 @@
private static final String EOS_AND_DECODE_ONLY_ERROR_MESSAGE = "An input buffer cannot have "
+ "both BUFFER_FLAG_END_OF_STREAM and BUFFER_FLAG_DECODE_ONLY flags";
private static final int CB_CRYPTO_ERROR = 6;
+ private static final int CB_LARGE_FRAME_OUTPUT_AVAILABLE = 7;
private class EventHandler extends Handler {
private MediaCodec mCodec;
@@ -1945,6 +1951,39 @@
break;
}
+ case CB_LARGE_FRAME_OUTPUT_AVAILABLE:
+ {
+ int index = msg.arg2;
+ ArrayDeque<BufferInfo> infos = (ArrayDeque<BufferInfo>)msg.obj;
+ synchronized(mBufferLock) {
+ switch (mBufferMode) {
+ case BUFFER_MODE_LEGACY:
+ validateOutputByteBuffersLocked(mCachedOutputBuffers,
+ index, infos);
+ break;
+ case BUFFER_MODE_BLOCK:
+ while (mOutputFrames.size() <= index) {
+ mOutputFrames.add(null);
+ }
+ OutputFrame frame = mOutputFrames.get(index);
+ if (frame == null) {
+ frame = new OutputFrame(index);
+ mOutputFrames.set(index, frame);
+ }
+ frame.setBufferInfos(infos);
+ frame.setAccessible(true);
+ break;
+ default:
+ throw new IllegalArgumentException(
+ "Unrecognized buffer mode: for large frame output");
+ }
+ }
+ mCallback.onOutputBuffersAvailable(
+ mCodec, index, infos);
+
+ break;
+ }
+
case CB_ERROR:
{
mCallback.onError(mCodec, (MediaCodec.CodecException) msg.obj);
@@ -2836,11 +2875,72 @@
}
}
+ /**
+ * Submit multiple access units to the codec along with multiple
+ * {@link MediaCodec.BufferInfo} describing the contents of the buffer. This method
+ * is supported only in asynchronous mode. While this method can be used for all codecs,
+ * it is meant for buffer batching, which is only supported by codecs that advertise
+ * FEATURE_MultipleFrames. Other codecs will not output large output buffers via
+ * onOutputBuffersAvailable, and instead will output single-access-unit output via
+ * onOutputBufferAvailable.
+ * <p>
+ * Output buffer size can be configured using the following MediaFormat keys.
+ * {@link MediaFormat#KEY_BUFFER_BATCH_MAX_OUTPUT_SIZE} and
+ * {@link MediaFormat#KEY_BUFFER_BATCH_THRESHOLD_OUTPUT_SIZE}.
+ * Details for each access unit present in the buffer should be described using
+ * {@link MediaCodec.BufferInfo}. Access units must be laid out contiguously (without any gaps)
+ * and in order. Multiple access units in the output if present, will be available in
+ * {@link Callback#onOutputBuffersAvailable} or {@link Callback#onOutputBufferAvailable}
+ * in case of single-access-unit output or when output does not contain any buffers,
+ * such as flags.
+ * <p>
+ * All other details for populating {@link MediaCodec.BufferInfo} is the same as described in
+ * {@link #queueInputBuffer}.
+ *
+ * @param index The index of a client-owned input buffer previously returned
+ * in a call to {@link #dequeueInputBuffer}.
+ * @param bufferInfos ArrayDeque of {@link MediaCodec.BufferInfo} that describes the
+ * contents in the buffer. The ArrayDeque and the BufferInfo objects provided
+ * can be recycled by the caller for re-use.
+ * @throws IllegalStateException if not in the Executing state or not in asynchronous mode.
+ * @throws MediaCodec.CodecException upon codec error.
+ * @throws IllegalArgumentException upon if bufferInfos is empty, contains null, or if the
+ * access units are not contiguous.
+ * @throws CryptoException if a crypto object has been specified in
+ * {@link #configure}
+ */
+ @FlaggedApi(FLAG_LARGE_AUDIO_FRAME)
+ public final void queueInputBuffers(
+ int index,
+ @NonNull ArrayDeque<BufferInfo> bufferInfos) {
+ synchronized(mBufferLock) {
+ if (mBufferMode == BUFFER_MODE_BLOCK) {
+ throw new IncompatibleWithBlockModelException("queueInputBuffers() "
+ + "is not compatible with CONFIGURE_FLAG_USE_BLOCK_MODEL. "
+ + "Please use getQueueRequest() to queue buffers");
+ }
+ invalidateByteBufferLocked(mCachedInputBuffers, index, true /* input */);
+ mDequeuedInputBuffers.remove(index);
+ }
+ try {
+ native_queueInputBuffers(
+ index, bufferInfos.toArray());
+ } catch (CryptoException | IllegalStateException | IllegalArgumentException e) {
+ revalidateByteBuffer(mCachedInputBuffers, index, true /* input */);
+ throw e;
+ }
+ }
+
private native final void native_queueInputBuffer(
int index,
int offset, int size, long presentationTimeUs, int flags)
throws CryptoException;
+ private native final void native_queueInputBuffers(
+ int index,
+ @NonNull Object[] infos)
+ throws CryptoException, CodecException;
+
public static final int CRYPTO_MODE_UNENCRYPTED = 0;
public static final int CRYPTO_MODE_AES_CTR = 1;
public static final int CRYPTO_MODE_AES_CBC = 2;
@@ -3464,6 +3564,26 @@
}
/**
+ * Sets MediaCodec.BufferInfo objects describing the access units
+ * contained in this queue request. Access units must be laid out
+ * contiguously without gaps and in order.
+ *
+ * @param infos Represents {@link MediaCodec.BufferInfo} objects to mark
+ * individual access-unit boundaries and the timestamps associated with it.
+ * The buffer is expected to contain the data in a continuous manner.
+ * @return this object
+ */
+ @FlaggedApi(FLAG_LARGE_AUDIO_FRAME)
+ public @NonNull QueueRequest setBufferInfos(@NonNull ArrayDeque<BufferInfo> infos) {
+ if (!isAccessible()) {
+ throw new IllegalStateException("The request is stale");
+ }
+ mBufferInfos.clear();
+ mBufferInfos.addAll(infos);
+ return this;
+ }
+
+ /**
* Add an integer parameter.
* See {@link MediaFormat} for an exhaustive list of supported keys with
* values of type int, that can also be set with {@link MediaFormat#setInteger}.
@@ -3579,10 +3699,18 @@
throw new IllegalStateException("No block is set");
}
setAccessible(false);
+ if (mBufferInfos.isEmpty()) {
+ BufferInfo info = new BufferInfo();
+ info.size = mSize;
+ info.offset = mOffset;
+ info.presentationTimeUs = mPresentationTimeUs;
+ info.flags = mFlags;
+ mBufferInfos.add(info);
+ }
if (mLinearBlock != null) {
mCodec.native_queueLinearBlock(
- mIndex, mLinearBlock, mOffset, mSize, mCryptoInfo,
- mPresentationTimeUs, mFlags,
+ mIndex, mLinearBlock, mCryptoInfo,
+ mBufferInfos.toArray(),
mTuningKeys, mTuningValues);
} else if (mHardwareBuffer != null) {
mCodec.native_queueHardwareBuffer(
@@ -3600,6 +3728,7 @@
mHardwareBuffer = null;
mPresentationTimeUs = 0;
mFlags = 0;
+ mBufferInfos.clear();
mTuningKeys.clear();
mTuningValues.clear();
return this;
@@ -3623,6 +3752,7 @@
private HardwareBuffer mHardwareBuffer = null;
private long mPresentationTimeUs = 0;
private @BufferFlag int mFlags = 0;
+ private final ArrayDeque<BufferInfo> mBufferInfos = new ArrayDeque<>();
private final ArrayList<String> mTuningKeys = new ArrayList<>();
private final ArrayList<Object> mTuningValues = new ArrayList<>();
@@ -3632,11 +3762,8 @@
private native void native_queueLinearBlock(
int index,
@NonNull LinearBlock block,
- int offset,
- int size,
@Nullable CryptoInfo cryptoInfo,
- long presentationTimeUs,
- int flags,
+ @NonNull Object[] bufferInfos,
@NonNull ArrayList<String> keys,
@NonNull ArrayList<Object> values);
@@ -4050,6 +4177,27 @@
}
}
+ private void validateOutputByteBuffersLocked(
+ @Nullable ByteBuffer[] buffers, int index, @NonNull ArrayDeque<BufferInfo> infoDeque) {
+ Optional<BufferInfo> minInfo = infoDeque.stream().min(
+ (info1, info2) -> Integer.compare(info1.offset, info2.offset));
+ Optional<BufferInfo> maxInfo = infoDeque.stream().max(
+ (info1, info2) -> Integer.compare(info1.offset, info2.offset));
+ if (buffers == null) {
+ if (index >= 0) {
+ mValidOutputIndices.set(index);
+ }
+ } else if (index >= 0 && index < buffers.length) {
+ ByteBuffer buffer = buffers[index];
+ if (buffer != null && minInfo.isPresent() && maxInfo.isPresent()) {
+ buffer.setAccessible(true);
+ buffer.limit(maxInfo.get().offset + maxInfo.get().size);
+ buffer.position(minInfo.get().offset);
+ }
+ }
+
+ }
+
private void validateOutputByteBufferLocked(
@Nullable ByteBuffer[] buffers, int index, @NonNull BufferInfo info) {
if (buffers == null) {
@@ -4407,6 +4555,22 @@
return mFlags;
}
+ /*
+ * Returns the BufferInfos associated with this OutputFrame. These BufferInfos
+ * describes the access units present in the OutputFrame. Access units are laid
+ * out contiguously without gaps and in order.
+ */
+ @FlaggedApi(FLAG_LARGE_AUDIO_FRAME)
+ public @NonNull ArrayDeque<BufferInfo> getBufferInfos() {
+ if (mBufferInfos.isEmpty()) {
+ // single BufferInfo could be present.
+ BufferInfo bufferInfo = new BufferInfo();
+ bufferInfo.set(0, 0, mPresentationTimeUs, mFlags);
+ mBufferInfos.add(bufferInfo);
+ }
+ return mBufferInfos;
+ }
+
/**
* Returns a read-only {@link MediaFormat} for this frame. The returned
* object is valid only until the client calls {@link MediaCodec#releaseOutputBuffer}.
@@ -4432,6 +4596,7 @@
mLinearBlock = null;
mHardwareBuffer = null;
mFormat = null;
+ mBufferInfos.clear();
mChangedKeys.clear();
mKeySet.clear();
mLoaded = false;
@@ -4450,6 +4615,11 @@
mFlags = info.flags;
}
+ void setBufferInfos(ArrayDeque<BufferInfo> infos) {
+ mBufferInfos.clear();
+ mBufferInfos.addAll(infos);
+ }
+
boolean isLoaded() {
return mLoaded;
}
@@ -4464,6 +4634,7 @@
private long mPresentationTimeUs = 0;
private @BufferFlag int mFlags = 0;
private MediaFormat mFormat = null;
+ private final ArrayDeque<BufferInfo> mBufferInfos = new ArrayDeque<>();
private final ArrayList<String> mChangedKeys = new ArrayList<>();
private final Set<String> mKeySet = new HashSet<>();
private boolean mAccessible = false;
@@ -5172,6 +5343,32 @@
@NonNull MediaCodec codec, int index, @NonNull BufferInfo info);
/**
+ * Called when multiple access-units are available in the output.
+ *
+ * @param codec The MediaCodec object.
+ * @param index The index of the available output buffer.
+ * @param infos Infos describing the available output buffer {@link MediaCodec.BufferInfo}.
+ * Access units present in the output buffer are laid out contiguously
+ * without gaps and in order.
+ */
+ @FlaggedApi(FLAG_LARGE_AUDIO_FRAME)
+ public void onOutputBuffersAvailable(
+ @NonNull MediaCodec codec, int index, @NonNull ArrayDeque<BufferInfo> infos) {
+ /*
+ * This callback returns multiple BufferInfos when codecs are configured to operate on
+ * large audio frame. Since at this point, we have a single large buffer, returning
+ * each BufferInfo using
+ * {@link Callback#onOutputBufferAvailable onOutputBufferAvailable} may cause the
+ * index to be released to the codec using {@link MediaCodec#releaseOutputBuffer}
+ * before all BuffersInfos can be returned to the client.
+ * Hence this callback is required to be implemented or else an exception is thrown.
+ */
+ throw new IllegalStateException(
+ "Client must override onOutputBuffersAvailable when codec is " +
+ "configured to operate with multiple access units");
+ }
+
+ /**
* Called when the MediaCodec encountered an error
*
* @param codec The MediaCodec object.
diff --git a/media/java/android/media/MediaMuxer.java b/media/java/android/media/MediaMuxer.java
index 30f4562..80b606c 100644
--- a/media/java/android/media/MediaMuxer.java
+++ b/media/java/android/media/MediaMuxer.java
@@ -514,7 +514,7 @@
* The following table summarizes support for specific format keys across android releases.
* Keys marked with '+:' are required.
*
- * <table style="width: 0%">
+ * <table>
* <thead>
* <tr>
* <th rowspan=2>OS Version(s)</th>
@@ -583,7 +583,7 @@
* <p>
* The following table summarizes codec support for containers across android releases:
*
- * <table style="width: 0%">
+ * <table>
* <thead>
* <tr>
* <th rowspan=2>OS Version(s)</th>
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index aa30748..bdfa6301 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -65,7 +65,8 @@
*
* <p>A common case of using MediaRecorder to record audio works as follows:
*
- * <pre>MediaRecorder recorder = new MediaRecorder();
+ * <pre>
+ * MediaRecorder recorder = new MediaRecorder(context);
* recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
* recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
* recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
diff --git a/media/java/android/media/projection/IMediaProjection.aidl b/media/java/android/media/projection/IMediaProjection.aidl
index 388b2c5..2fb0af5 100644
--- a/media/java/android/media/projection/IMediaProjection.aidl
+++ b/media/java/android/media/projection/IMediaProjection.aidl
@@ -18,6 +18,7 @@
import android.media.projection.IMediaProjectionCallback;
import android.os.IBinder;
+import android.app.ActivityOptions.LaunchCookie;
/** {@hide} */
interface IMediaProjection {
@@ -38,22 +39,22 @@
void unregisterCallback(IMediaProjectionCallback callback);
/**
- * Returns the {@link android.os.IBinder} identifying the task to record, or {@code null} if
+ * Returns the {@link LaunchCookie} identifying the task to record, or {@code null} if
* there is none.
*/
@EnforcePermission("MANAGE_MEDIA_PROJECTION")
@JavaPassthrough(annotation = "@android.annotation.RequiresPermission(android.Manifest"
+ ".permission.MANAGE_MEDIA_PROJECTION)")
- IBinder getLaunchCookie();
+ LaunchCookie getLaunchCookie();
/**
- * Updates the {@link android.os.IBinder} identifying the task to record, or {@code null} if
+ * Updates the {@link LaunchCookie} identifying the task to record, or {@code null} if
* there is none.
*/
@EnforcePermission("MANAGE_MEDIA_PROJECTION")
@JavaPassthrough(annotation = "@android.annotation.RequiresPermission(android.Manifest"
+ ".permission.MANAGE_MEDIA_PROJECTION)")
- void setLaunchCookie(in IBinder launchCookie);
+ void setLaunchCookie(in LaunchCookie launchCookie);
/**
* Returns {@code true} if this token is still valid. A token is valid as long as the token
diff --git a/media/java/android/media/projection/MediaProjectionInfo.java b/media/java/android/media/projection/MediaProjectionInfo.java
index c820392..cd0763d 100644
--- a/media/java/android/media/projection/MediaProjectionInfo.java
+++ b/media/java/android/media/projection/MediaProjectionInfo.java
@@ -16,7 +16,7 @@
package android.media.projection;
-import android.os.IBinder;
+import android.app.ActivityOptions.LaunchCookie;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.UserHandle;
@@ -27,9 +27,9 @@
public final class MediaProjectionInfo implements Parcelable {
private final String mPackageName;
private final UserHandle mUserHandle;
- private final IBinder mLaunchCookie;
+ private final LaunchCookie mLaunchCookie;
- public MediaProjectionInfo(String packageName, UserHandle handle, IBinder launchCookie) {
+ public MediaProjectionInfo(String packageName, UserHandle handle, LaunchCookie launchCookie) {
mPackageName = packageName;
mUserHandle = handle;
mLaunchCookie = launchCookie;
@@ -38,7 +38,7 @@
public MediaProjectionInfo(Parcel in) {
mPackageName = in.readString();
mUserHandle = UserHandle.readFromParcel(in);
- mLaunchCookie = in.readStrongBinder();
+ mLaunchCookie = LaunchCookie.readFromParcel(in);
}
public String getPackageName() {
@@ -49,7 +49,7 @@
return mUserHandle;
}
- public IBinder getLaunchCookie() {
+ public LaunchCookie getLaunchCookie() {
return mLaunchCookie;
}
@@ -72,7 +72,7 @@
public String toString() {
return "MediaProjectionInfo{mPackageName="
+ mPackageName + ", mUserHandle="
- + mUserHandle + ", mLaunchCookie"
+ + mUserHandle + ", mLaunchCookie="
+ mLaunchCookie + "}";
}
@@ -85,7 +85,7 @@
public void writeToParcel(Parcel out, int flags) {
out.writeString(mPackageName);
UserHandle.writeToParcel(mUserHandle, out);
- out.writeStrongBinder(mLaunchCookie);
+ LaunchCookie.writeToParcel(mLaunchCookie, out);
}
public static final @android.annotation.NonNull Parcelable.Creator<MediaProjectionInfo> CREATOR =
diff --git a/media/java/android/media/projection/MediaProjectionManager.java b/media/java/android/media/projection/MediaProjectionManager.java
index 9790d02..e3290d6 100644
--- a/media/java/android/media/projection/MediaProjectionManager.java
+++ b/media/java/android/media/projection/MediaProjectionManager.java
@@ -18,8 +18,11 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SuppressLint;
import android.annotation.SystemService;
+import android.annotation.TestApi;
import android.app.Activity;
+import android.app.ActivityOptions.LaunchCookie;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -73,6 +76,9 @@
/** @hide */
public static final String EXTRA_MEDIA_PROJECTION =
"android.media.projection.extra.EXTRA_MEDIA_PROJECTION";
+ /** @hide */
+ public static final String EXTRA_LAUNCH_COOKIE =
+ "android.media.projection.extra.EXTRA_LAUNCH_COOKIE";
/** @hide */
public static final int TYPE_SCREEN_CAPTURE = 0;
@@ -158,17 +164,29 @@
*/
@NonNull
public Intent createScreenCaptureIntent(@NonNull MediaProjectionConfig config) {
- Intent i = new Intent();
- final ComponentName mediaProjectionPermissionDialogComponent =
- ComponentName.unflattenFromString(mContext.getResources()
- .getString(com.android.internal.R.string
- .config_mediaProjectionPermissionDialogComponent));
- i.setComponent(mediaProjectionPermissionDialogComponent);
+ Intent i = createScreenCaptureIntent();
i.putExtra(EXTRA_MEDIA_PROJECTION_CONFIG, config);
return i;
}
/**
+ * Returns an intent similar to {@link #createScreenCaptureIntent()} that will enable screen
+ * recording of the task with the specified launch cookie. This method should only be used for
+ * testing.
+ *
+ * @param launchCookie the launch cookie corresponding to the task to record.
+ * @hide
+ */
+ @SuppressLint("UnflaggedApi")
+ @TestApi
+ @NonNull
+ public Intent createScreenCaptureIntent(@Nullable LaunchCookie launchCookie) {
+ Intent i = createScreenCaptureIntent();
+ i.putExtra(EXTRA_LAUNCH_COOKIE, launchCookie);
+ return i;
+ }
+
+ /**
* Retrieves the {@link MediaProjection} obtained from a successful screen
* capture request. The result code and data from the request are provided by overriding
* {@link Activity#onActivityResult(int, int, Intent) onActivityResult(int, int, Intent)},
diff --git a/media/java/android/media/tv/SignalingDataRequest.aidl b/media/java/android/media/tv/SignalingDataRequest.aidl
new file mode 100644
index 0000000..29e89fe
--- /dev/null
+++ b/media/java/android/media/tv/SignalingDataRequest.aidl
@@ -0,0 +1,3 @@
+package android.media.tv;
+
+parcelable SignalingDataRequest;
diff --git a/media/java/android/media/tv/SignalingDataRequest.java b/media/java/android/media/tv/SignalingDataRequest.java
new file mode 100644
index 0000000..dcf1d48
--- /dev/null
+++ b/media/java/android/media/tv/SignalingDataRequest.java
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.tv;
+
+import android.annotation.NonNull;
+import android.os.Parcelable;
+
+/**
+ * Request to retrieve the Low-level Signalling Tables (LLS) and Service-layer Signalling (SLS)
+ * metadata.
+ *
+ * <p>For more details on each type of metadata that can be requested, refer to the ATSC standard
+ * A/344:2023-5 9.2.10 - Query Signaling Data API.
+ *
+ * @hide
+ */
+public class SignalingDataRequest extends BroadcastInfoRequest implements Parcelable {
+ private static final @TvInputManager.BroadcastInfoType int REQUEST_TYPE =
+ TvInputManager.BROADCAST_INFO_TYPE_SIGNALING_DATA;
+
+ public static final @NonNull Parcelable.Creator<SignalingDataRequest> CREATOR =
+ new Parcelable.Creator<SignalingDataRequest>() {
+ @Override
+ public SignalingDataRequest[] newArray(int size) {
+ return new SignalingDataRequest[size];
+ }
+
+ @Override
+ public SignalingDataRequest createFromParcel(@NonNull android.os.Parcel in) {
+ return new SignalingDataRequest(in);
+ }
+ };
+
+ /** SLS Metadata: All metadata objects for the requested service(s) */
+ public static final int SLS_METADATA_ALL = 0x7FFFFFF;
+
+ /** SLS Metadata: APD for the requested service(s) */
+ public static final int SLS_METADATA_APD = 1;
+
+ /** SLS Metadata: USBD for the requested service(s) */
+ public static final int SLS_METADATA_USBD = 1 << 1;
+
+ /** SLS Metadata: S-TSID for the requested service(s) */
+ public static final int SLS_METADATA_STSID = 1 << 2;
+
+ /** SLS Metadata: DASH MPD for the requested service(s) */
+ public static final int SLS_METADATA_MPD = 1 << 3;
+
+ /** SLS Metadata: User Service Description for MMTP */
+ public static final int SLS_METADATA_USD = 1 << 4;
+
+ /** SLS Metadata: MMT Package Access Table for the requested service(s) */
+ public static final int SLS_METADATA_PAT = 1 << 5;
+
+ /** SLS Metadata: MMT Package Table for the requested service(s) */
+ public static final int SLS_METADATA_MPT = 1 << 6;
+
+ /** SLS Metadata: MMT Media Presentation Information Table for the requested service(s) */
+ public static final int SLS_METADATA_MPIT = 1 << 7;
+
+ /** SLS Metadata: MMT Clock Relation Information for the requested service(s) */
+ public static final int SLS_METADATA_CRIT = 1 << 8;
+
+ /** SLS Metadata: MMT Device Capabilities Information Table for the requested service(s) */
+ public static final int SLS_METADATA_DCIT = 1 << 9;
+
+ /** SLS Metadata: HTML Entry Pages Location Description for the requested service(s) */
+ public static final int SLS_METADATA_HELD = 1 << 10;
+
+ /** SLS Metadata: Distribution Window Desciription for the requested service(s) */
+ public static final int SLS_METADATA_DWD = 1 << 11;
+
+ /** SLS Metadata: MMT Application Event Information for the requested service(s) */
+ public static final int SLS_METADATA_AEI = 1 << 12;
+
+ /** SLS Metadata: Video Stream Properties Descriptor */
+ public static final int SLS_METADATA_VSPD = 1 << 13;
+
+ /** SLS Metadata: ATSC Staggercast Descriptor */
+ public static final int SLS_METADATA_ASD = 1 << 14;
+
+ /** SLS Metadata: Inband Event Descriptor */
+ public static final int SLS_METADATA_IED = 1 << 15;
+
+ /** SLS Metadata: Caption Asset Descriptor */
+ public static final int SLS_METADATA_CAD = 1 << 16;
+
+ /** SLS Metadata: Audio Stream Properties Descriptor */
+ public static final int SLS_METADATA_ASPD = 1 << 17;
+
+ /** SLS Metadata: Security Properties Descriptor */
+ public static final int SLS_METADATA_SSD = 1 << 18;
+
+ /** SLS Metadata: ROUTE/DASH Application Dynamic Event for the requested service(s) */
+ public static final int SLS_METADATA_EMSG = 1 << 19;
+
+ /** SLS Metadata: MMT Application Dynamic Event for the requested service(s) */
+ public static final int SLS_METADATA_EVTI = 1 << 20;
+
+ /** Regional Service Availability Table for the requested service(s) */
+ public static final int SLS_METADATA_RSAT = 1 << 21;
+
+ private final int mGroup;
+ private @NonNull final int[] mLlsTableIds;
+ private final int mSlsMetadataTypes;
+
+ SignalingDataRequest(
+ int requestId,
+ int option,
+ int group,
+ @NonNull int[] llsTableIds,
+ int slsMetadataTypes) {
+ super(REQUEST_TYPE, requestId, option);
+ mGroup = group;
+ mLlsTableIds = llsTableIds;
+ mSlsMetadataTypes = slsMetadataTypes;
+ }
+
+ SignalingDataRequest(@NonNull android.os.Parcel in) {
+ super(REQUEST_TYPE, in);
+
+ int group = in.readInt();
+ int[] llsTableIds = in.createIntArray();
+ int slsMetadataTypes = in.readInt();
+
+ this.mGroup = group;
+ this.mLlsTableIds = llsTableIds;
+ com.android.internal.util.AnnotationValidations.validate(NonNull.class, null, mLlsTableIds);
+ this.mSlsMetadataTypes = slsMetadataTypes;
+ }
+
+ public int getGroup() {
+ return mGroup;
+ }
+
+ public @NonNull int[] getLlsTableIds() {
+ return mLlsTableIds;
+ }
+
+ public int getSlsMetadataTypes() {
+ return mSlsMetadataTypes;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull android.os.Parcel dest, int flags) {
+ super.writeToParcel(dest, flags);
+ dest.writeInt(mGroup);
+ dest.writeIntArray(mLlsTableIds);
+ dest.writeInt(mSlsMetadataTypes);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+}
diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java
index 2b31bfe..be1b675 100644
--- a/media/java/android/media/tv/TvInputManager.java
+++ b/media/java/android/media/tv/TvInputManager.java
@@ -489,10 +489,19 @@
/** @hide */
@Retention(RetentionPolicy.SOURCE)
- @IntDef(prefix = "BROADCAST_INFO_TYPE_", value =
- {BROADCAST_INFO_TYPE_TS, BROADCAST_INFO_TYPE_TABLE, BROADCAST_INFO_TYPE_SECTION,
- BROADCAST_INFO_TYPE_PES, BROADCAST_INFO_STREAM_EVENT, BROADCAST_INFO_TYPE_DSMCC,
- BROADCAST_INFO_TYPE_COMMAND, BROADCAST_INFO_TYPE_TIMELINE})
+ @IntDef(
+ prefix = "BROADCAST_INFO_TYPE_",
+ value = {
+ BROADCAST_INFO_TYPE_TS,
+ BROADCAST_INFO_TYPE_TABLE,
+ BROADCAST_INFO_TYPE_SECTION,
+ BROADCAST_INFO_TYPE_PES,
+ BROADCAST_INFO_STREAM_EVENT,
+ BROADCAST_INFO_TYPE_DSMCC,
+ BROADCAST_INFO_TYPE_COMMAND,
+ BROADCAST_INFO_TYPE_TIMELINE,
+ BROADCAST_INFO_TYPE_SIGNALING_DATA
+ })
public @interface BroadcastInfoType {}
public static final int BROADCAST_INFO_TYPE_TS = 1;
@@ -505,6 +514,9 @@
public static final int BROADCAST_INFO_TYPE_TIMELINE = 8;
/** @hide */
+ public static final int BROADCAST_INFO_TYPE_SIGNALING_DATA = 9;
+
+ /** @hide */
@Retention(RetentionPolicy.SOURCE)
@IntDef(prefix = "SIGNAL_STRENGTH_",
value = {SIGNAL_STRENGTH_LOST, SIGNAL_STRENGTH_WEAK, SIGNAL_STRENGTH_STRONG})
diff --git a/media/java/android/media/tv/interactive/ITvInteractiveAppClient.aidl b/media/java/android/media/tv/interactive/ITvInteractiveAppClient.aidl
index 7b58531..1404d7c 100644
--- a/media/java/android/media/tv/interactive/ITvInteractiveAppClient.aidl
+++ b/media/java/android/media/tv/interactive/ITvInteractiveAppClient.aidl
@@ -63,6 +63,8 @@
void onRequestTvRecordingInfoList(in int type, int seq);
void onRequestSigning(in String id, in String algorithm, in String alias, in byte[] data,
int seq);
+ void onRequestSigning2(in String id, in String algorithm, in String host,
+ int port, in byte[] data, int seq);
void onRequestCertificate(in String host, int port, int seq);
void onAdRequest(in AdRequest request, int Seq);
}
diff --git a/media/java/android/media/tv/interactive/ITvInteractiveAppSessionCallback.aidl b/media/java/android/media/tv/interactive/ITvInteractiveAppSessionCallback.aidl
index cb89181..3c91a3e 100644
--- a/media/java/android/media/tv/interactive/ITvInteractiveAppSessionCallback.aidl
+++ b/media/java/android/media/tv/interactive/ITvInteractiveAppSessionCallback.aidl
@@ -61,6 +61,7 @@
void onRequestTvRecordingInfo(in String recordingId);
void onRequestTvRecordingInfoList(in int type);
void onRequestSigning(in String id, in String algorithm, in String alias, in byte[] data);
+ void onRequestSigning2(in String id, in String algorithm, in String host, int port, in byte[] data);
void onRequestCertificate(in String host, int port);
void onAdRequest(in AdRequest request);
}
diff --git a/media/java/android/media/tv/interactive/TvInteractiveAppManager.java b/media/java/android/media/tv/interactive/TvInteractiveAppManager.java
index 011744f..498eec6 100755
--- a/media/java/android/media/tv/interactive/TvInteractiveAppManager.java
+++ b/media/java/android/media/tv/interactive/TvInteractiveAppManager.java
@@ -657,6 +657,19 @@
}
@Override
+ public void onRequestSigning2(
+ String id, String algorithm, String host, int port, byte[] data, int seq) {
+ synchronized (mSessionCallbackRecordMap) {
+ SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
+ if (record == null) {
+ Log.e(TAG, "Callback not found for seq " + seq);
+ return;
+ }
+ record.postRequestSigning(id, algorithm, host, port, data);
+ }
+ }
+
+ @Override
public void onRequestCertificate(String host, int port, int seq) {
synchronized (mSessionCallbackRecordMap) {
SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
@@ -2258,6 +2271,17 @@
});
}
+ void postRequestSigning(String id, String algorithm, String host, int port,
+ byte[] data) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mSessionCallback.onRequestSigning(mSession, id, algorithm, host,
+ port, data);
+ }
+ });
+ }
+
void postRequestCertificate(String host, int port) {
mHandler.post(new Runnable() {
@Override
@@ -2609,6 +2633,25 @@
}
/**
+ * This is called when
+ * {@link TvInteractiveAppService.Session#requestSigning(String, String, String, int, byte[])} is
+ * called.
+ *
+ * @param session A {@link TvInteractiveAppService.Session} associated with this callback.
+ * @param signingId the ID to identify the request.
+ * @param algorithm the standard name of the signature algorithm requested, such as
+ * MD5withRSA, SHA256withDSA, etc.
+ * @param host The host of the SSL CLient Authentication Server
+ * @param port The port of the SSL Client Authentication Server
+ * @param data the original bytes to be signed.
+ * @hide
+ */
+ public void onRequestSigning(
+ Session session, String signingId, String algorithm, String host,
+ int port, byte[] data) {
+ }
+
+ /**
* This is called when the service requests a SSL certificate for client validation.
*
* @param session A {@link TvInteractiveAppService.Session} associated with this callback.
diff --git a/media/java/android/media/tv/interactive/TvInteractiveAppService.java b/media/java/android/media/tv/interactive/TvInteractiveAppService.java
index 054b272..7b6dc38 100755
--- a/media/java/android/media/tv/interactive/TvInteractiveAppService.java
+++ b/media/java/android/media/tv/interactive/TvInteractiveAppService.java
@@ -1645,6 +1645,50 @@
}
/**
+ * Requests signing of the given data.
+ *
+ * <p>This is used when the corresponding server of the broadcast-independent interactive
+ * app requires signing during handshaking, and the interactive app service doesn't have
+ * the built-in private key. The private key is provided by the content providers and
+ * pre-built in the related app, such as TV app.
+ *
+ * @param signingId the ID to identify the request. When a result is received, this ID can
+ * be used to correlate the result with the request.
+ * @param algorithm the standard name of the signature algorithm requested, such as
+ * MD5withRSA, SHA256withDSA, etc. The name is from standards like
+ * FIPS PUB 186-4 and PKCS #1.
+ * @param host the host of the SSL client authentication server.
+ * @param port the port of the SSL client authentication server.
+ * @param data the original bytes to be signed.
+ *
+ * @see #onSigningResult(String, byte[])
+ * @see TvInteractiveAppView#createBiInteractiveApp(Uri, Bundle)
+ * @see TvInteractiveAppView#BI_INTERACTIVE_APP_KEY_ALIAS
+ * @hide
+ */
+ @CallSuper
+ public void requestSigning(@NonNull String signingId, @NonNull String algorithm,
+ @NonNull String host, int port, @NonNull byte[] data) {
+ executeOrPostRunnableOnMainThread(new Runnable() {
+ @MainThread
+ @Override
+ public void run() {
+ try {
+ if (DEBUG) {
+ Log.d(TAG, "requestSigning");
+ }
+ if (mSessionCallback != null) {
+ mSessionCallback.onRequestSigning2(signingId, algorithm,
+ host, port, data);
+ }
+ } catch (RemoteException e) {
+ Log.w(TAG, "error in requestSigning", e);
+ }
+ }
+ });
+ }
+
+ /**
* Requests a SSL certificate for client validation.
*
* @param host the host name of the SSL authentication server.
diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp
index ef90bf9..8cdd59e 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -163,6 +163,13 @@
static struct {
jclass clazz;
jmethodID ctorId;
+ jmethodID sizeId;
+ jmethodID addId;
+} gArrayDequeInfo;
+
+static struct {
+ jclass clazz;
+ jmethodID ctorId;
jmethodID setInternalStateId;
jfieldID contextId;
jfieldID validId;
@@ -200,8 +207,14 @@
jfieldID queueRequestIndexID;
jfieldID outputFrameLinearBlockID;
jfieldID outputFrameHardwareBufferID;
+ jfieldID outputFramebufferInfosID;
jfieldID outputFrameChangedKeysID;
jfieldID outputFrameFormatID;
+ jfieldID bufferInfoFlags;
+ jfieldID bufferInfoOffset;
+ jfieldID bufferInfoSize;
+ jfieldID bufferInfoPresentationTimeUs;
+
};
static fields_t gFields;
@@ -412,6 +425,22 @@
index, offset, size, timeUs, flags, errorDetailMsg);
}
+status_t JMediaCodec::queueInputBuffers(
+ size_t index,
+ size_t offset,
+ size_t size,
+ const sp<RefBase> &infos,
+ AString *errorDetailMsg) {
+
+ sp<BufferInfosWrapper> auInfo((BufferInfosWrapper *)infos.get());
+ return mCodec->queueInputBuffers(
+ index,
+ offset,
+ size,
+ auInfo,
+ errorDetailMsg);
+}
+
status_t JMediaCodec::queueSecureInputBuffer(
size_t index,
size_t offset,
@@ -430,10 +459,11 @@
}
status_t JMediaCodec::queueBuffer(
- size_t index, const std::shared_ptr<C2Buffer> &buffer, int64_t timeUs,
- uint32_t flags, const sp<AMessage> &tunings, AString *errorDetailMsg) {
+ size_t index, const std::shared_ptr<C2Buffer> &buffer,
+ const sp<RefBase> &infos, const sp<AMessage> &tunings, AString *errorDetailMsg) {
+ sp<BufferInfosWrapper> auInfo((BufferInfosWrapper *)infos.get());
return mCodec->queueBuffer(
- index, buffer, timeUs, flags, tunings, errorDetailMsg);
+ index, buffer, auInfo, tunings, errorDetailMsg);
}
status_t JMediaCodec::queueEncryptedLinearBlock(
@@ -446,13 +476,13 @@
const uint8_t iv[16],
CryptoPlugin::Mode mode,
const CryptoPlugin::Pattern &pattern,
- int64_t presentationTimeUs,
- uint32_t flags,
+ const sp<RefBase> &infos,
const sp<AMessage> &tunings,
AString *errorDetailMsg) {
+ sp<BufferInfosWrapper> auInfo((BufferInfosWrapper *)infos.get());
return mCodec->queueEncryptedBuffer(
index, buffer, offset, subSamples, numSubSamples, key, iv, mode, pattern,
- presentationTimeUs, flags, tunings, errorDetailMsg);
+ auInfo, tunings, errorDetailMsg);
}
status_t JMediaCodec::dequeueInputBuffer(size_t *index, int64_t timeoutUs) {
@@ -722,6 +752,42 @@
return OK;
}
+void maybeSetBufferInfos(JNIEnv *env, jobject &frame, const sp<BufferInfosWrapper> &bufInfos) {
+ if (!bufInfos) {
+ return;
+ }
+ std::vector<AccessUnitInfo> &infos = bufInfos.get()->value;
+ if (infos.empty()) {
+ return;
+ }
+ ScopedLocalRef<jobject> dequeObj{env, env->NewObject(
+ gArrayDequeInfo.clazz, gArrayDequeInfo.ctorId)};
+ jint offset = 0;
+ std::vector<jobject> jObjectInfos;
+ for (int i = 0 ; i < infos.size(); i++) {
+ jobject bufferInfo = env->NewObject(
+ gBufferInfo.clazz, gBufferInfo.ctorId);
+ if (bufferInfo != NULL) {
+ env->CallVoidMethod(bufferInfo, gBufferInfo.setId,
+ offset,
+ (jint)(infos)[i].mSize,
+ (infos)[i].mTimestamp,
+ (infos)[i].mFlags);
+ (void)env->CallBooleanMethod(
+ dequeObj.get(), gArrayDequeInfo.addId, bufferInfo);
+ offset += (infos)[i].mSize;
+ jObjectInfos.push_back(bufferInfo);
+ }
+ }
+ env->SetObjectField(
+ frame,
+ gFields.outputFramebufferInfosID,
+ dequeObj.get());
+ for (int i = 0; i < jObjectInfos.size(); i++) {
+ env->DeleteLocalRef(jObjectInfos[i]);
+ }
+}
+
status_t JMediaCodec::getOutputFrame(
JNIEnv *env, jobject frame, size_t index) const {
sp<MediaCodecBuffer> buffer;
@@ -732,6 +798,11 @@
}
if (buffer->size() > 0) {
+ sp<RefBase> obj;
+ sp<BufferInfosWrapper> bufInfos;
+ if (buffer->meta()->findObject("accessUnitInfo", &obj)) {
+ bufInfos = std::move(((decltype(bufInfos.get()))obj.get()));
+ }
std::shared_ptr<C2Buffer> c2Buffer = buffer->asC2Buffer();
if (c2Buffer) {
switch (c2Buffer->data().type()) {
@@ -747,6 +818,7 @@
(jlong)context.release(),
true);
env->SetObjectField(frame, gFields.outputFrameLinearBlockID, linearBlock.get());
+ maybeSetBufferInfos(env, frame, bufInfos);
break;
}
case C2BufferData::GRAPHIC: {
@@ -787,6 +859,7 @@
(jlong)context.release(),
true);
env->SetObjectField(frame, gFields.outputFrameLinearBlockID, linearBlock.get());
+ maybeSetBufferInfos(env, frame, bufInfos);
} else {
// No-op.
}
@@ -1250,6 +1323,7 @@
void JMediaCodec::handleCallback(const sp<AMessage> &msg) {
int32_t arg1, arg2 = 0;
jobject obj = NULL;
+ std::vector<jobject> jObjectInfos;
CHECK(msg->findInt32("callbackID", &arg1));
JNIEnv *env = AndroidRuntime::getJNIEnv();
@@ -1287,6 +1361,35 @@
break;
}
+ case MediaCodec::CB_LARGE_FRAME_OUTPUT_AVAILABLE:
+ {
+ sp<RefBase> spobj = nullptr;
+ CHECK(msg->findInt32("index", &arg2));
+ CHECK(msg->findObject("accessUnitInfo", &spobj));
+ if (spobj != nullptr) {
+ sp<BufferInfosWrapper> bufferInfoParamsWrapper {
+ (BufferInfosWrapper *)spobj.get()};
+ std::vector<AccessUnitInfo> &bufferInfoParams =
+ bufferInfoParamsWrapper.get()->value;
+ obj = env->NewObject(gArrayDequeInfo.clazz, gArrayDequeInfo.ctorId);
+ jint offset = 0;
+ for (int i = 0 ; i < bufferInfoParams.size(); i++) {
+ jobject bufferInfo = env->NewObject(gBufferInfo.clazz, gBufferInfo.ctorId);
+ if (bufferInfo != NULL) {
+ env->CallVoidMethod(bufferInfo, gBufferInfo.setId,
+ offset,
+ (jint)(bufferInfoParams)[i].mSize,
+ (bufferInfoParams)[i].mTimestamp,
+ (bufferInfoParams)[i].mFlags);
+ (void)env->CallBooleanMethod(obj, gArrayDequeInfo.addId, bufferInfo);
+ offset += (bufferInfoParams)[i].mSize;
+ jObjectInfos.push_back(bufferInfo);
+ }
+ }
+ }
+ break;
+ }
+
case MediaCodec::CB_CRYPTO_ERROR:
{
int32_t err, actionCode;
@@ -1346,6 +1449,9 @@
arg2,
obj);
+ for (int i = 0; i < jObjectInfos.size(); i++) {
+ env->DeleteLocalRef(jObjectInfos[i]);
+ }
env->DeleteLocalRef(obj);
}
@@ -1913,6 +2019,103 @@
codec->getExceptionMessage(errorDetailMsg.c_str()).c_str());
}
+static status_t extractInfosFromObject(
+ JNIEnv * const env,
+ jint * const initialOffset,
+ jint * const totalSize,
+ std::vector<AccessUnitInfo> * const infos,
+ const jobjectArray &objArray,
+ AString * const errorDetailMsg) {
+ if (totalSize == nullptr
+ || initialOffset == nullptr
+ || infos == nullptr) {
+ if (errorDetailMsg) {
+ *errorDetailMsg = "Error: Null arguments provided for extracting Access unit info";
+ }
+ return BAD_VALUE;
+ }
+ const jsize numEntries = env->GetArrayLength(objArray);
+ if (numEntries <= 0) {
+ if (errorDetailMsg) {
+ *errorDetailMsg = "Error: No BufferInfo found while queuing for large frame input";
+ }
+ return BAD_VALUE;
+ }
+ *initialOffset = 0;
+ *totalSize = 0;
+ for (jsize i = 0; i < numEntries; i++) {
+ jobject param = env->GetObjectArrayElement(objArray, i);
+ if (param == NULL) {
+ if (errorDetailMsg) {
+ *errorDetailMsg = "Error: Queuing a null BufferInfo";
+ }
+ return BAD_VALUE;
+ }
+ size_t offset = static_cast<size_t>(env->GetIntField(param, gFields.bufferInfoOffset));
+ size_t size = static_cast<size_t>(env->GetIntField(param, gFields.bufferInfoSize));
+ uint32_t flags = static_cast<uint32_t>(env->GetIntField(param, gFields.bufferInfoFlags));
+ if (flags == 0 && size == 0) {
+ if (errorDetailMsg) {
+ *errorDetailMsg = "Error: Queuing an empty BufferInfo";
+ }
+ return BAD_VALUE;
+ }
+ if (i == 0) {
+ *initialOffset = offset;
+ }
+ if (CC_UNLIKELY((offset > UINT32_MAX)
+ || ((long)(offset + size) > UINT32_MAX)
+ || ((offset - *initialOffset) != *totalSize))) {
+ if (errorDetailMsg) {
+ *errorDetailMsg = "Error: offset/size in BufferInfo";
+ }
+ return BAD_VALUE;
+ }
+ infos->emplace_back(
+ flags,
+ size,
+ env->GetLongField(param, gFields.bufferInfoPresentationTimeUs));
+ *totalSize += size;
+ }
+ return OK;
+}
+
+static void android_media_MediaCodec_queueInputBuffers(
+ JNIEnv *env,
+ jobject thiz,
+ jint index,
+ jobjectArray objArray) {
+ ALOGV("android_media_MediaCodec_queueInputBuffers");
+ sp<JMediaCodec> codec = getMediaCodec(env, thiz);
+ if (codec == NULL || codec->initCheck() != OK || objArray == NULL) {
+ throwExceptionAsNecessary(env, INVALID_OPERATION, codec);
+ return;
+ }
+ sp<BufferInfosWrapper> infoObj =
+ new BufferInfosWrapper{decltype(infoObj->value)()};
+ AString errorDetailMsg;
+ jint initialOffset = 0;
+ jint totalSize = 0;
+ status_t err = extractInfosFromObject(
+ env,
+ &initialOffset,
+ &totalSize,
+ &infoObj->value,
+ objArray,
+ &errorDetailMsg);
+ if (err == OK) {
+ err = codec->queueInputBuffers(
+ index,
+ initialOffset,
+ totalSize,
+ infoObj,
+ &errorDetailMsg);
+ }
+ throwExceptionAsNecessary(
+ env, err, ACTION_CODE_FATAL,
+ codec->getExceptionMessage(errorDetailMsg.c_str()).c_str());
+}
+
struct NativeCryptoInfo {
NativeCryptoInfo(JNIEnv *env, jobject cryptoInfoObj)
: mEnv{env},
@@ -2559,8 +2762,7 @@
static void android_media_MediaCodec_native_queueLinearBlock(
JNIEnv *env, jobject thiz, jint index, jobject bufferObj,
- jint offset, jint size, jobject cryptoInfoObj,
- jlong presentationTimeUs, jint flags, jobject keys, jobject values) {
+ jobject cryptoInfoObj, jobjectArray objArray, jobject keys, jobject values) {
ALOGV("android_media_MediaCodec_native_queueLinearBlock");
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
@@ -2578,7 +2780,24 @@
"error occurred while converting tunings from Java to native");
return;
}
-
+ jint totalSize;
+ jint initialOffset;
+ std::vector<AccessUnitInfo> infoVec;
+ AString errorDetailMsg;
+ err = extractInfosFromObject(env,
+ &initialOffset,
+ &totalSize,
+ &infoVec,
+ objArray,
+ &errorDetailMsg);
+ if (err != OK) {
+ throwExceptionAsNecessary(
+ env, INVALID_OPERATION, ACTION_CODE_FATAL,
+ codec->getExceptionMessage(errorDetailMsg.c_str()).c_str());
+ return;
+ }
+ sp<BufferInfosWrapper> infos =
+ new BufferInfosWrapper{std::move(infoVec)};
std::shared_ptr<C2Buffer> buffer;
sp<hardware::HidlMemory> memory;
ScopedLocalRef<jobject> lock{env, env->GetObjectField(bufferObj, gLinearBlockInfo.lockId)};
@@ -2587,10 +2806,10 @@
JMediaCodecLinearBlock *context =
(JMediaCodecLinearBlock *)env->GetLongField(bufferObj, gLinearBlockInfo.contextId);
if (codec->hasCryptoOrDescrambler()) {
- extractMemoryFromContext(context, offset, size, &memory);
- offset += context->mHidlMemoryOffset;
+ extractMemoryFromContext(context, initialOffset, totalSize, &memory);
+ initialOffset += context->mHidlMemoryOffset;
} else {
- extractBufferFromContext(context, offset, size, &buffer);
+ extractBufferFromContext(context, initialOffset, totalSize, &buffer);
}
}
env->MonitorExit(lock.get());
@@ -2601,7 +2820,6 @@
return;
}
- AString errorDetailMsg;
if (codec->hasCryptoOrDescrambler()) {
if (!memory) {
// It means there was an unexpected failure in extractMemoryFromContext above
@@ -2615,7 +2833,7 @@
return;
}
auto cryptoInfo =
- cryptoInfoObj ? NativeCryptoInfo{env, cryptoInfoObj} : NativeCryptoInfo{size};
+ cryptoInfoObj ? NativeCryptoInfo{env, cryptoInfoObj} : NativeCryptoInfo{totalSize};
if (env->ExceptionCheck()) {
// Creation of cryptoInfo failed. Let the exception bubble up.
return;
@@ -2623,13 +2841,12 @@
err = codec->queueEncryptedLinearBlock(
index,
memory,
- offset,
+ initialOffset,
cryptoInfo.mSubSamples, cryptoInfo.mNumSubSamples,
(const uint8_t *)cryptoInfo.mKey, (const uint8_t *)cryptoInfo.mIv,
cryptoInfo.mMode,
cryptoInfo.mPattern,
- presentationTimeUs,
- flags,
+ infos,
tunings,
&errorDetailMsg);
ALOGI_IF(err != OK, "queueEncryptedLinearBlock returned err = %d", err);
@@ -2646,7 +2863,7 @@
return;
}
err = codec->queueBuffer(
- index, buffer, presentationTimeUs, flags, tunings, &errorDetailMsg);
+ index, buffer, infos, tunings, &errorDetailMsg);
}
throwExceptionAsNecessary(
env, err, ACTION_CODE_FATAL,
@@ -2704,8 +2921,11 @@
std::shared_ptr<C2Buffer> buffer = C2Buffer::CreateGraphicBuffer(block->share(
block->crop(), C2Fence{}));
AString errorDetailMsg;
+ sp<BufferInfosWrapper> infos =
+ new BufferInfosWrapper{decltype(infos->value)()};
+ infos->value.emplace_back(flags, 0 /*not used*/, presentationTimeUs);
err = codec->queueBuffer(
- index, buffer, presentationTimeUs, flags, tunings, &errorDetailMsg);
+ index, buffer, infos, tunings, &errorDetailMsg);
throwExceptionAsNecessary(
env, err, ACTION_CODE_FATAL,
codec->getExceptionMessage(errorDetailMsg.c_str()).c_str());
@@ -3214,6 +3434,10 @@
env->GetFieldID(clazz.get(), "mLinearBlock", "Landroid/media/MediaCodec$LinearBlock;");
CHECK(gFields.outputFrameLinearBlockID != NULL);
+ gFields.outputFramebufferInfosID =
+ env->GetFieldID(clazz.get(), "mBufferInfos", "Ljava/util/ArrayDeque;");
+ CHECK(gFields.outputFramebufferInfosID != NULL);
+
gFields.outputFrameHardwareBufferID =
env->GetFieldID(clazz.get(), "mHardwareBuffer", "Landroid/hardware/HardwareBuffer;");
CHECK(gFields.outputFrameHardwareBufferID != NULL);
@@ -3401,6 +3625,19 @@
gArrayListInfo.addId = env->GetMethodID(clazz.get(), "add", "(Ljava/lang/Object;)Z");
CHECK(gArrayListInfo.addId != NULL);
+ clazz.reset(env->FindClass("java/util/ArrayDeque"));
+ CHECK(clazz.get() != NULL);
+ gArrayDequeInfo.clazz = (jclass)env->NewGlobalRef(clazz.get());
+
+ gArrayDequeInfo.ctorId = env->GetMethodID(clazz.get(), "<init>", "()V");
+ CHECK(gArrayDequeInfo.ctorId != NULL);
+
+ gArrayDequeInfo.sizeId = env->GetMethodID(clazz.get(), "size", "()I");
+ CHECK(gArrayDequeInfo.sizeId != NULL);
+
+ gArrayDequeInfo.addId = env->GetMethodID(clazz.get(), "add", "(Ljava/lang/Object;)Z");
+ CHECK(gArrayDequeInfo.addId != NULL);
+
clazz.reset(env->FindClass("android/media/MediaCodec$LinearBlock"));
CHECK(clazz.get() != NULL);
@@ -3444,6 +3681,12 @@
gBufferInfo.setId = env->GetMethodID(clazz.get(), "set", "(IIJI)V");
CHECK(gBufferInfo.setId != NULL);
+
+ gFields.bufferInfoSize = env->GetFieldID(clazz.get(), "size", "I");
+ gFields.bufferInfoFlags = env->GetFieldID(clazz.get(), "flags", "I");
+ gFields.bufferInfoOffset = env->GetFieldID(clazz.get(), "offset", "I");
+ gFields.bufferInfoPresentationTimeUs =
+ env->GetFieldID(clazz.get(), "presentationTimeUs", "J");
}
static void android_media_MediaCodec_native_setup(
@@ -3701,6 +3944,9 @@
{ "native_queueInputBuffer", "(IIIJI)V",
(void *)android_media_MediaCodec_queueInputBuffer },
+ { "native_queueInputBuffers", "(I[Ljava/lang/Object;)V",
+ (void *)android_media_MediaCodec_queueInputBuffers },
+
{ "native_queueSecureInputBuffer", "(IILandroid/media/MediaCodec$CryptoInfo;JI)V",
(void *)android_media_MediaCodec_queueSecureInputBuffer },
@@ -3711,8 +3957,8 @@
{ "native_closeMediaImage", "(J)V", (void *)android_media_MediaCodec_closeMediaImage },
{ "native_queueLinearBlock",
- "(ILandroid/media/MediaCodec$LinearBlock;IILandroid/media/MediaCodec$CryptoInfo;JI"
- "Ljava/util/ArrayList;Ljava/util/ArrayList;)V",
+ "(ILandroid/media/MediaCodec$LinearBlock;Landroid/media/MediaCodec$CryptoInfo;"
+ "[Ljava/lang/Object;Ljava/util/ArrayList;Ljava/util/ArrayList;)V",
(void *)android_media_MediaCodec_native_queueLinearBlock },
{ "native_queueHardwareBuffer",
diff --git a/media/jni/android_media_MediaCodec.h b/media/jni/android_media_MediaCodec.h
index fbaf64f..02708ef 100644
--- a/media/jni/android_media_MediaCodec.h
+++ b/media/jni/android_media_MediaCodec.h
@@ -35,6 +35,7 @@
namespace android {
struct ABuffer;
+struct AccessUnitInfo;
struct ALooper;
struct AMessage;
struct AString;
@@ -93,6 +94,13 @@
size_t offset, size_t size, int64_t timeUs, uint32_t flags,
AString *errorDetailMsg);
+ status_t queueInputBuffers(
+ size_t index,
+ size_t offset,
+ size_t size,
+ const sp<RefBase> &auInfo,
+ AString *errorDetailMsg = NULL);
+
status_t queueSecureInputBuffer(
size_t index,
size_t offset,
@@ -108,7 +116,7 @@
status_t queueBuffer(
size_t index, const std::shared_ptr<C2Buffer> &buffer,
- int64_t timeUs, uint32_t flags, const sp<AMessage> &tunings,
+ const sp<RefBase> &infos, const sp<AMessage> &tunings,
AString *errorDetailMsg);
status_t queueEncryptedLinearBlock(
@@ -121,8 +129,7 @@
const uint8_t iv[16],
CryptoPlugin::Mode mode,
const CryptoPlugin::Pattern &pattern,
- int64_t presentationTimeUs,
- uint32_t flags,
+ const sp<RefBase> &infos,
const sp<AMessage> &tunings,
AString *errorDetailMsg);
diff --git a/media/jni/soundpool/SoundDecoder.cpp b/media/jni/soundpool/SoundDecoder.cpp
index 5ed10b0..ae57634 100644
--- a/media/jni/soundpool/SoundDecoder.cpp
+++ b/media/jni/soundpool/SoundDecoder.cpp
@@ -29,14 +29,15 @@
// before the SoundDecoder thread closes.
static constexpr int32_t kWaitTimeBeforeCloseMs = 1000;
-SoundDecoder::SoundDecoder(SoundManager* soundManager, size_t threads)
+SoundDecoder::SoundDecoder(SoundManager* soundManager, size_t threads, int32_t threadPriority)
: mSoundManager(soundManager)
{
ALOGV("%s(%p, %zu)", __func__, soundManager, threads);
// ThreadPool is created, but we don't launch any threads.
mThreadPool = std::make_unique<ThreadPool>(
std::min(threads, (size_t)std::thread::hardware_concurrency()),
- "SoundDecoder_");
+ "SoundDecoder_",
+ threadPriority);
}
SoundDecoder::~SoundDecoder()
diff --git a/media/jni/soundpool/SoundDecoder.h b/media/jni/soundpool/SoundDecoder.h
index 7b62114..3f44a0d 100644
--- a/media/jni/soundpool/SoundDecoder.h
+++ b/media/jni/soundpool/SoundDecoder.h
@@ -28,7 +28,7 @@
*/
class SoundDecoder {
public:
- SoundDecoder(SoundManager* soundManager, size_t threads);
+ SoundDecoder(SoundManager* soundManager, size_t threads, int32_t threadPriority);
~SoundDecoder();
void loadSound(int32_t soundID) NO_THREAD_SAFETY_ANALYSIS; // uses unique_lock
void quit();
diff --git a/media/jni/soundpool/SoundManager.cpp b/media/jni/soundpool/SoundManager.cpp
index 5b16174..fa35813 100644
--- a/media/jni/soundpool/SoundManager.cpp
+++ b/media/jni/soundpool/SoundManager.cpp
@@ -29,7 +29,7 @@
static const size_t kDecoderThreads = std::thread::hardware_concurrency() >= 4 ? 2 : 1;
SoundManager::SoundManager()
- : mDecoder{std::make_unique<SoundDecoder>(this, kDecoderThreads)}
+ : mDecoder{std::make_unique<SoundDecoder>(this, kDecoderThreads, ANDROID_PRIORITY_NORMAL)}
{
ALOGV("%s()", __func__);
}
diff --git a/media/jni/soundpool/StreamManager.cpp b/media/jni/soundpool/StreamManager.cpp
index 66fec1c..e11ccbc 100644
--- a/media/jni/soundpool/StreamManager.cpp
+++ b/media/jni/soundpool/StreamManager.cpp
@@ -126,7 +126,8 @@
mThreadPool = std::make_unique<ThreadPool>(
std::min((size_t)streams, // do not make more threads than streams to play
std::min(threads, (size_t)std::thread::hardware_concurrency())),
- "SoundPool_");
+ "SoundPool_",
+ ANDROID_PRIORITY_AUDIO);
}
#pragma clang diagnostic pop
diff --git a/media/jni/soundpool/StreamManager.h b/media/jni/soundpool/StreamManager.h
index 340b49b..a4cb286 100644
--- a/media/jni/soundpool/StreamManager.h
+++ b/media/jni/soundpool/StreamManager.h
@@ -46,9 +46,9 @@
*/
class JavaThread {
public:
- JavaThread(std::function<void()> f, const char *name)
+ JavaThread(std::function<void()> f, const char *name, int32_t threadPriority)
: mF{std::move(f)} {
- createThreadEtc(staticFunction, this, name, ANDROID_PRIORITY_AUDIO);
+ createThreadEtc(staticFunction, this, name, threadPriority);
}
JavaThread(JavaThread &&) = delete; // uses "this" ptr, not moveable.
@@ -109,9 +109,11 @@
*/
class ThreadPool {
public:
- ThreadPool(size_t maxThreadCount, std::string name)
+ ThreadPool(size_t maxThreadCount, std::string name,
+ int32_t threadPriority = ANDROID_PRIORITY_NORMAL)
: mMaxThreadCount(maxThreadCount)
- , mName{std::move(name)} { }
+ , mName{std::move(name)}
+ , mThreadPriority(threadPriority) {}
~ThreadPool() { quit(); }
@@ -159,7 +161,8 @@
const int32_t id = mNextThreadId;
mThreads.emplace_back(std::make_unique<JavaThread>(
[this, id, mf = std::move(f)] { mf(id); --mActiveThreadCount; },
- (mName + std::to_string(id)).c_str()));
+ (mName + std::to_string(id)).c_str(),
+ mThreadPriority));
++mActiveThreadCount;
return id;
}
@@ -180,6 +183,7 @@
private:
const size_t mMaxThreadCount;
const std::string mName;
+ const int32_t mThreadPriority;
std::atomic_size_t mActiveThreadCount = 0;
diff --git a/media/tests/projection/src/android/media/projection/FakeIMediaProjection.java b/media/tests/projection/src/android/media/projection/FakeIMediaProjection.java
index 774de5f..0df36af 100644
--- a/media/tests/projection/src/android/media/projection/FakeIMediaProjection.java
+++ b/media/tests/projection/src/android/media/projection/FakeIMediaProjection.java
@@ -19,7 +19,7 @@
import static android.Manifest.permission.MANAGE_MEDIA_PROJECTION;
import android.annotation.EnforcePermission;
-import android.os.IBinder;
+import android.app.ActivityOptions.LaunchCookie;
import android.os.PermissionEnforcer;
import android.os.RemoteException;
@@ -29,7 +29,7 @@
*/
public final class FakeIMediaProjection extends IMediaProjection.Stub {
boolean mIsStarted = false;
- IBinder mLaunchCookie = null;
+ LaunchCookie mLaunchCookie = null;
IMediaProjectionCallback mIMediaProjectionCallback = null;
FakeIMediaProjection(PermissionEnforcer enforcer) {
@@ -80,14 +80,14 @@
@Override
@EnforcePermission(MANAGE_MEDIA_PROJECTION)
- public IBinder getLaunchCookie() throws RemoteException {
+ public LaunchCookie getLaunchCookie() throws RemoteException {
getLaunchCookie_enforcePermission();
return mLaunchCookie;
}
@Override
@EnforcePermission(MANAGE_MEDIA_PROJECTION)
- public void setLaunchCookie(IBinder launchCookie) throws RemoteException {
+ public void setLaunchCookie(LaunchCookie launchCookie) throws RemoteException {
setLaunchCookie_enforcePermission();
mLaunchCookie = launchCookie;
}
diff --git a/media/tests/projection/src/android/media/projection/MediaProjectionTest.java b/media/tests/projection/src/android/media/projection/MediaProjectionTest.java
index 2e0396f..1323e89 100644
--- a/media/tests/projection/src/android/media/projection/MediaProjectionTest.java
+++ b/media/tests/projection/src/android/media/projection/MediaProjectionTest.java
@@ -31,15 +31,14 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
import android.annotation.Nullable;
+import android.app.ActivityOptions.LaunchCookie;
import android.compat.testing.PlatformCompatChangeRule;
import android.hardware.display.DisplayManager;
import android.hardware.display.VirtualDisplay;
import android.hardware.display.VirtualDisplayConfig;
import android.os.Handler;
-import android.os.IBinder;
import android.os.Looper;
import android.os.RemoteException;
import android.os.test.FakePermissionEnforcer;
@@ -117,7 +116,7 @@
permissionEnforcer.grant(MANAGE_MEDIA_PROJECTION);
// Support the MediaProjection instance.
mFakeIMediaProjection = new FakeIMediaProjection(permissionEnforcer);
- mFakeIMediaProjection.setLaunchCookie(mock(IBinder.class));
+ mFakeIMediaProjection.setLaunchCookie(new LaunchCookie());
mMediaProjection = new MediaProjection(mTestableContext, mFakeIMediaProjection,
mDisplayManager);
diff --git a/nfc/jarjar-rules.txt b/nfc/jarjar-rules.txt
index 4cd652d..99ae144 100644
--- a/nfc/jarjar-rules.txt
+++ b/nfc/jarjar-rules.txt
@@ -4,6 +4,7 @@
rule android.content.IntentProto* com.android.nfc.x.@0
rule android.content.IntentFilterProto* com.android.nfc.x.@0
rule android.content.AuthorityEntryProto* com.android.nfc.x.@0
+rule android.content.UriRelativeFilter* com.android.nfc.x.@0
rule android.nfc.cardemulation.AidGroupProto* com.android.nfc.x.@0
rule android.nfc.cardemulation.ApduServiceInfoProto* com.android.nfc.x.@0
rule android.nfc.cardemulation.NfcFServiceInfoProto* com.android.nfc.x.@0
diff --git a/nfc/java/android/nfc/cardemulation/CardEmulation.java b/nfc/java/android/nfc/cardemulation/CardEmulation.java
index 9d38e4c..1f41b81 100644
--- a/nfc/java/android/nfc/cardemulation/CardEmulation.java
+++ b/nfc/java/android/nfc/cardemulation/CardEmulation.java
@@ -338,8 +338,10 @@
}
}
/**
- * Sets whether the system should default to observe mode or not when
- * the service is in the foreground or the default payment service.
+ * Sets whether the system should default to observe mode or not when the service is in the
+ * foreground or the default payment service. The default is to not enable observe mode when
+ * a service either the foreground default service or the default payment service so not
+ * calling this method will preserve that behavior.
*
* @param service The component name of the service
* @param enable Whether the servic should default to observe mode or not
diff --git a/packages/CrashRecovery/aconfig/flags.aconfig b/packages/CrashRecovery/aconfig/flags.aconfig
new file mode 100644
index 0000000..5636266
--- /dev/null
+++ b/packages/CrashRecovery/aconfig/flags.aconfig
@@ -0,0 +1,9 @@
+package: "android.crashrecovery.flags"
+
+flag {
+ name: "recoverability_detection"
+ namespace: "package_watchdog"
+ description: "Feature flag for recoverability detection"
+ bug: "310236690"
+ is_fixed_read_only: true
+}
\ No newline at end of file
diff --git a/packages/CredentialManager/res/values-af/strings.xml b/packages/CredentialManager/res/values-af/strings.xml
index a2d2a96..3614240 100644
--- a/packages/CredentialManager/res/values-af/strings.xml
+++ b/packages/CredentialManager/res/values-af/strings.xml
@@ -92,4 +92,8 @@
<string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Van ’n ander toestel af"</string>
<string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Gebruik ’n ander toestel"</string>
<string name="request_cancelled_by" msgid="3735222326886267820">"Versoek is deur <xliff:g id="APP_NAME">%1$s</xliff:g> gekanselleer"</string>
+ <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+ <skip />
+ <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+ <skip />
</resources>
diff --git a/packages/CredentialManager/res/values-am/strings.xml b/packages/CredentialManager/res/values-am/strings.xml
index 475dcf7..e5759fa 100644
--- a/packages/CredentialManager/res/values-am/strings.xml
+++ b/packages/CredentialManager/res/values-am/strings.xml
@@ -92,4 +92,8 @@
<string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"ከሌላ መሣሪያ"</string>
<string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"የተለየ መሣሪያ ይጠቀሙ"</string>
<string name="request_cancelled_by" msgid="3735222326886267820">"ጥያቄ በ<xliff:g id="APP_NAME">%1$s</xliff:g> ተሰርዟል"</string>
+ <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+ <skip />
+ <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+ <skip />
</resources>
diff --git a/packages/CredentialManager/res/values-ar/strings.xml b/packages/CredentialManager/res/values-ar/strings.xml
index 3f85b58..fdd9043 100644
--- a/packages/CredentialManager/res/values-ar/strings.xml
+++ b/packages/CredentialManager/res/values-ar/strings.xml
@@ -92,4 +92,8 @@
<string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"من جهاز آخر"</string>
<string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"استخدام جهاز مختلف"</string>
<string name="request_cancelled_by" msgid="3735222326886267820">"تم إلغاء الطلب بواسطة \"<xliff:g id="APP_NAME">%1$s</xliff:g>\"."</string>
+ <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+ <skip />
+ <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+ <skip />
</resources>
diff --git a/packages/CredentialManager/res/values-as/strings.xml b/packages/CredentialManager/res/values-as/strings.xml
index e14b34b..005079e 100644
--- a/packages/CredentialManager/res/values-as/strings.xml
+++ b/packages/CredentialManager/res/values-as/strings.xml
@@ -92,4 +92,8 @@
<string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"অন্য এটা ডিভাইচৰ পৰা"</string>
<string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"অন্য এটা ডিভাইচ ব্যৱহাৰ কৰক"</string>
<string name="request_cancelled_by" msgid="3735222326886267820">"<xliff:g id="APP_NAME">%1$s</xliff:g>এ অনুৰোধটো বাতিল কৰিছে"</string>
+ <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+ <skip />
+ <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+ <skip />
</resources>
diff --git a/packages/CredentialManager/res/values-az/strings.xml b/packages/CredentialManager/res/values-az/strings.xml
index d0f8bb0..9937942 100644
--- a/packages/CredentialManager/res/values-az/strings.xml
+++ b/packages/CredentialManager/res/values-az/strings.xml
@@ -92,4 +92,8 @@
<string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Başqa cihazdan"</string>
<string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Başqa cihaz istifadə edin"</string>
<string name="request_cancelled_by" msgid="3735222326886267820">"<xliff:g id="APP_NAME">%1$s</xliff:g> sorğunu ləğv etdi"</string>
+ <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+ <skip />
+ <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+ <skip />
</resources>
diff --git a/packages/CredentialManager/res/values-b+sr+Latn/strings.xml b/packages/CredentialManager/res/values-b+sr+Latn/strings.xml
index 780274c..171e841 100644
--- a/packages/CredentialManager/res/values-b+sr+Latn/strings.xml
+++ b/packages/CredentialManager/res/values-b+sr+Latn/strings.xml
@@ -92,4 +92,8 @@
<string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Sa drugog uređaja"</string>
<string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Koristi drugi uređaj"</string>
<string name="request_cancelled_by" msgid="3735222326886267820">"Zahtve je otkazala aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+ <skip />
+ <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+ <skip />
</resources>
diff --git a/packages/CredentialManager/res/values-be/strings.xml b/packages/CredentialManager/res/values-be/strings.xml
index 144bb86..323b683 100644
--- a/packages/CredentialManager/res/values-be/strings.xml
+++ b/packages/CredentialManager/res/values-be/strings.xml
@@ -92,4 +92,8 @@
<string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"З іншай прылады"</string>
<string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Скарыстаць іншую прыладу"</string>
<string name="request_cancelled_by" msgid="3735222326886267820">"Запыт скасаваны праграмай \"<xliff:g id="APP_NAME">%1$s</xliff:g>\""</string>
+ <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+ <skip />
+ <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+ <skip />
</resources>
diff --git a/packages/CredentialManager/res/values-bg/strings.xml b/packages/CredentialManager/res/values-bg/strings.xml
index ef4dd54c..1efec45 100644
--- a/packages/CredentialManager/res/values-bg/strings.xml
+++ b/packages/CredentialManager/res/values-bg/strings.xml
@@ -92,4 +92,8 @@
<string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"От друго устройство"</string>
<string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Използване на друго устройство"</string>
<string name="request_cancelled_by" msgid="3735222326886267820">"Заявката е анулирана от <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+ <skip />
+ <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+ <skip />
</resources>
diff --git a/packages/CredentialManager/res/values-bn/strings.xml b/packages/CredentialManager/res/values-bn/strings.xml
index 14f4a9b..3fcc91a 100644
--- a/packages/CredentialManager/res/values-bn/strings.xml
+++ b/packages/CredentialManager/res/values-bn/strings.xml
@@ -92,4 +92,8 @@
<string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"অন্য ডিভাইস থেকে"</string>
<string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"আলাদা ডিভাইস ব্যবহার করুন"</string>
<string name="request_cancelled_by" msgid="3735222326886267820">"<xliff:g id="APP_NAME">%1$s</xliff:g> দ্বারা অনুরোধ বাতিল করা হয়েছে"</string>
+ <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+ <skip />
+ <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+ <skip />
</resources>
diff --git a/packages/CredentialManager/res/values-bs/strings.xml b/packages/CredentialManager/res/values-bs/strings.xml
index 6315ea8..6a3d25e 100644
--- a/packages/CredentialManager/res/values-bs/strings.xml
+++ b/packages/CredentialManager/res/values-bs/strings.xml
@@ -92,4 +92,8 @@
<string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"S drugog uređaja"</string>
<string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Upotrijebite drugi uređaj"</string>
<string name="request_cancelled_by" msgid="3735222326886267820">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> je otkazala zahtjev"</string>
+ <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+ <skip />
+ <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+ <skip />
</resources>
diff --git a/packages/CredentialManager/res/values-ca/strings.xml b/packages/CredentialManager/res/values-ca/strings.xml
index 8e3fda8..d491b70 100644
--- a/packages/CredentialManager/res/values-ca/strings.xml
+++ b/packages/CredentialManager/res/values-ca/strings.xml
@@ -92,4 +92,8 @@
<string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Des d\'un altre dispositiu"</string>
<string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Utilitza un dispositiu diferent"</string>
<string name="request_cancelled_by" msgid="3735222326886267820">"<xliff:g id="APP_NAME">%1$s</xliff:g> ha cancel·lat la sol·licitud"</string>
+ <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+ <skip />
+ <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+ <skip />
</resources>
diff --git a/packages/CredentialManager/res/values-cs/strings.xml b/packages/CredentialManager/res/values-cs/strings.xml
index 9fe5a49..133f3f8 100644
--- a/packages/CredentialManager/res/values-cs/strings.xml
+++ b/packages/CredentialManager/res/values-cs/strings.xml
@@ -92,4 +92,8 @@
<string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Z jiného zařízení"</string>
<string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Použít jiné zařízení"</string>
<string name="request_cancelled_by" msgid="3735222326886267820">"Aplikace <xliff:g id="APP_NAME">%1$s</xliff:g> žádost zrušila"</string>
+ <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+ <skip />
+ <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+ <skip />
</resources>
diff --git a/packages/CredentialManager/res/values-da/strings.xml b/packages/CredentialManager/res/values-da/strings.xml
index c7ee038..93de75f 100644
--- a/packages/CredentialManager/res/values-da/strings.xml
+++ b/packages/CredentialManager/res/values-da/strings.xml
@@ -92,4 +92,8 @@
<string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Fra en anden enhed"</string>
<string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Brug en anden enhed"</string>
<string name="request_cancelled_by" msgid="3735222326886267820">"Anmodningen blev annulleret af <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+ <skip />
+ <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+ <skip />
</resources>
diff --git a/packages/CredentialManager/res/values-de/strings.xml b/packages/CredentialManager/res/values-de/strings.xml
index 29d9a86b..d3648a1 100644
--- a/packages/CredentialManager/res/values-de/strings.xml
+++ b/packages/CredentialManager/res/values-de/strings.xml
@@ -92,4 +92,8 @@
<string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Von einem anderen Gerät"</string>
<string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Anderes Gerät verwenden"</string>
<string name="request_cancelled_by" msgid="3735222326886267820">"Anfrage abgebrochen von <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+ <skip />
+ <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+ <skip />
</resources>
diff --git a/packages/CredentialManager/res/values-el/strings.xml b/packages/CredentialManager/res/values-el/strings.xml
index 089f898..da3ae13 100644
--- a/packages/CredentialManager/res/values-el/strings.xml
+++ b/packages/CredentialManager/res/values-el/strings.xml
@@ -92,4 +92,8 @@
<string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Από άλλη συσκευή"</string>
<string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Χρήση διαφορετικής συσκευής"</string>
<string name="request_cancelled_by" msgid="3735222326886267820">"Το αίτημα ακυρώθηκε από την εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+ <skip />
+ <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+ <skip />
</resources>
diff --git a/packages/CredentialManager/res/values-en-rAU/strings.xml b/packages/CredentialManager/res/values-en-rAU/strings.xml
index 7b80db0..056b8ff 100644
--- a/packages/CredentialManager/res/values-en-rAU/strings.xml
+++ b/packages/CredentialManager/res/values-en-rAU/strings.xml
@@ -92,4 +92,8 @@
<string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"From another device"</string>
<string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Use a different device"</string>
<string name="request_cancelled_by" msgid="3735222326886267820">"Request cancelled by <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+ <skip />
+ <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+ <skip />
</resources>
diff --git a/packages/CredentialManager/res/values-en-rCA/strings.xml b/packages/CredentialManager/res/values-en-rCA/strings.xml
index b173616..e23711f 100644
--- a/packages/CredentialManager/res/values-en-rCA/strings.xml
+++ b/packages/CredentialManager/res/values-en-rCA/strings.xml
@@ -92,4 +92,8 @@
<string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"From another device"</string>
<string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Use a different device"</string>
<string name="request_cancelled_by" msgid="3735222326886267820">"Request cancelled by <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+ <skip />
+ <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+ <skip />
</resources>
diff --git a/packages/CredentialManager/res/values-en-rGB/strings.xml b/packages/CredentialManager/res/values-en-rGB/strings.xml
index 7b80db0..056b8ff 100644
--- a/packages/CredentialManager/res/values-en-rGB/strings.xml
+++ b/packages/CredentialManager/res/values-en-rGB/strings.xml
@@ -92,4 +92,8 @@
<string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"From another device"</string>
<string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Use a different device"</string>
<string name="request_cancelled_by" msgid="3735222326886267820">"Request cancelled by <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+ <skip />
+ <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+ <skip />
</resources>
diff --git a/packages/CredentialManager/res/values-en-rIN/strings.xml b/packages/CredentialManager/res/values-en-rIN/strings.xml
index 7b80db0..056b8ff 100644
--- a/packages/CredentialManager/res/values-en-rIN/strings.xml
+++ b/packages/CredentialManager/res/values-en-rIN/strings.xml
@@ -92,4 +92,8 @@
<string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"From another device"</string>
<string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Use a different device"</string>
<string name="request_cancelled_by" msgid="3735222326886267820">"Request cancelled by <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+ <skip />
+ <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+ <skip />
</resources>
diff --git a/packages/CredentialManager/res/values-en-rXC/strings.xml b/packages/CredentialManager/res/values-en-rXC/strings.xml
index c3eeb04..0db7324 100644
--- a/packages/CredentialManager/res/values-en-rXC/strings.xml
+++ b/packages/CredentialManager/res/values-en-rXC/strings.xml
@@ -92,4 +92,8 @@
<string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"From another device"</string>
<string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Use a different device"</string>
<string name="request_cancelled_by" msgid="3735222326886267820">"Request cancelled by <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+ <skip />
+ <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+ <skip />
</resources>
diff --git a/packages/CredentialManager/res/values-es-rUS/strings.xml b/packages/CredentialManager/res/values-es-rUS/strings.xml
index f6a5dcb..818d715 100644
--- a/packages/CredentialManager/res/values-es-rUS/strings.xml
+++ b/packages/CredentialManager/res/values-es-rUS/strings.xml
@@ -92,4 +92,8 @@
<string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Desde otro dispositivo"</string>
<string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Usar otra voz"</string>
<string name="request_cancelled_by" msgid="3735222326886267820">"<xliff:g id="APP_NAME">%1$s</xliff:g> canceló la solicitud"</string>
+ <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+ <skip />
+ <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+ <skip />
</resources>
diff --git a/packages/CredentialManager/res/values-es/strings.xml b/packages/CredentialManager/res/values-es/strings.xml
index fb0cbf9..f9776fb 100644
--- a/packages/CredentialManager/res/values-es/strings.xml
+++ b/packages/CredentialManager/res/values-es/strings.xml
@@ -92,4 +92,8 @@
<string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"De otro dispositivo"</string>
<string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Usar otro dispositivo"</string>
<string name="request_cancelled_by" msgid="3735222326886267820">"<xliff:g id="APP_NAME">%1$s</xliff:g> ha cancelado la solicitud"</string>
+ <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+ <skip />
+ <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+ <skip />
</resources>
diff --git a/packages/CredentialManager/res/values-et/strings.xml b/packages/CredentialManager/res/values-et/strings.xml
index 97dbe4d..4870e70 100644
--- a/packages/CredentialManager/res/values-et/strings.xml
+++ b/packages/CredentialManager/res/values-et/strings.xml
@@ -92,4 +92,8 @@
<string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Muus seadmes"</string>
<string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Kasuta teist seadet"</string>
<string name="request_cancelled_by" msgid="3735222326886267820">"Rakendus <xliff:g id="APP_NAME">%1$s</xliff:g> tühistas taotluse"</string>
+ <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+ <skip />
+ <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+ <skip />
</resources>
diff --git a/packages/CredentialManager/res/values-eu/strings.xml b/packages/CredentialManager/res/values-eu/strings.xml
index 8316283..21a66f9 100644
--- a/packages/CredentialManager/res/values-eu/strings.xml
+++ b/packages/CredentialManager/res/values-eu/strings.xml
@@ -92,4 +92,8 @@
<string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Beste gailu batean gordetakoak"</string>
<string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Erabili beste gailu bat"</string>
<string name="request_cancelled_by" msgid="3735222326886267820">"Utzi du bertan behera eskaera <xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioak"</string>
+ <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+ <skip />
+ <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+ <skip />
</resources>
diff --git a/packages/CredentialManager/res/values-fa/strings.xml b/packages/CredentialManager/res/values-fa/strings.xml
index a6e0d3d..47385cd 100644
--- a/packages/CredentialManager/res/values-fa/strings.xml
+++ b/packages/CredentialManager/res/values-fa/strings.xml
@@ -92,4 +92,8 @@
<string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"از دستگاهی دیگر"</string>
<string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"استفاده از دستگاه دیگری"</string>
<string name="request_cancelled_by" msgid="3735222326886267820">"درخواست را <xliff:g id="APP_NAME">%1$s</xliff:g> لغو کرد"</string>
+ <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+ <skip />
+ <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+ <skip />
</resources>
diff --git a/packages/CredentialManager/res/values-fi/strings.xml b/packages/CredentialManager/res/values-fi/strings.xml
index fff45c9..d463ea1 100644
--- a/packages/CredentialManager/res/values-fi/strings.xml
+++ b/packages/CredentialManager/res/values-fi/strings.xml
@@ -92,4 +92,8 @@
<string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Toiselta laitteelta"</string>
<string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Käytä toista laitetta"</string>
<string name="request_cancelled_by" msgid="3735222326886267820">"<xliff:g id="APP_NAME">%1$s</xliff:g> hylkäsi pyynnön"</string>
+ <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+ <skip />
+ <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+ <skip />
</resources>
diff --git a/packages/CredentialManager/res/values-fr-rCA/strings.xml b/packages/CredentialManager/res/values-fr-rCA/strings.xml
index 155be6f..3596604 100644
--- a/packages/CredentialManager/res/values-fr-rCA/strings.xml
+++ b/packages/CredentialManager/res/values-fr-rCA/strings.xml
@@ -92,4 +92,8 @@
<string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"À partir d\'un autre appareil"</string>
<string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Utiliser un autre appareil"</string>
<string name="request_cancelled_by" msgid="3735222326886267820">"Demande annulée par <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+ <skip />
+ <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+ <skip />
</resources>
diff --git a/packages/CredentialManager/res/values-fr/strings.xml b/packages/CredentialManager/res/values-fr/strings.xml
index e042815..fe545b3 100644
--- a/packages/CredentialManager/res/values-fr/strings.xml
+++ b/packages/CredentialManager/res/values-fr/strings.xml
@@ -92,4 +92,8 @@
<string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Depuis un autre appareil"</string>
<string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Utiliser un autre appareil"</string>
<string name="request_cancelled_by" msgid="3735222326886267820">"Requête annulée par <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+ <skip />
+ <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+ <skip />
</resources>
diff --git a/packages/CredentialManager/res/values-gl/strings.xml b/packages/CredentialManager/res/values-gl/strings.xml
index 79e0b5e..6341ed89 100644
--- a/packages/CredentialManager/res/values-gl/strings.xml
+++ b/packages/CredentialManager/res/values-gl/strings.xml
@@ -92,4 +92,8 @@
<string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Doutro dispositivo"</string>
<string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Usar outro dispositivo"</string>
<string name="request_cancelled_by" msgid="3735222326886267820">"<xliff:g id="APP_NAME">%1$s</xliff:g> cancelou a solicitude"</string>
+ <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+ <skip />
+ <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+ <skip />
</resources>
diff --git a/packages/CredentialManager/res/values-gu/strings.xml b/packages/CredentialManager/res/values-gu/strings.xml
index c3c5b62..19930df 100644
--- a/packages/CredentialManager/res/values-gu/strings.xml
+++ b/packages/CredentialManager/res/values-gu/strings.xml
@@ -92,4 +92,8 @@
<string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"કોઈ અન્ય ડિવાઇસમાંથી"</string>
<string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"કોઈ અન્ય ડિવાઇસનો ઉપયોગ કરો"</string>
<string name="request_cancelled_by" msgid="3735222326886267820">"<xliff:g id="APP_NAME">%1$s</xliff:g> દ્વારા વિનંતી રદ કરવામાં આવી"</string>
+ <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+ <skip />
+ <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+ <skip />
</resources>
diff --git a/packages/CredentialManager/res/values-hi/strings.xml b/packages/CredentialManager/res/values-hi/strings.xml
index 05d21e0..8505b19 100644
--- a/packages/CredentialManager/res/values-hi/strings.xml
+++ b/packages/CredentialManager/res/values-hi/strings.xml
@@ -92,4 +92,8 @@
<string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"किसी दूसरे डिवाइस से"</string>
<string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"दूसरे डिवाइस का इस्तेमाल करें"</string>
<string name="request_cancelled_by" msgid="3735222326886267820">"<xliff:g id="APP_NAME">%1$s</xliff:g> की ओर से अनुरोध रद्द किया गया"</string>
+ <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+ <skip />
+ <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+ <skip />
</resources>
diff --git a/packages/CredentialManager/res/values-hr/strings.xml b/packages/CredentialManager/res/values-hr/strings.xml
index 4425e24..3ea8847 100644
--- a/packages/CredentialManager/res/values-hr/strings.xml
+++ b/packages/CredentialManager/res/values-hr/strings.xml
@@ -92,4 +92,8 @@
<string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Na drugom uređaju"</string>
<string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Upotrijebite drugi uređaj"</string>
<string name="request_cancelled_by" msgid="3735222326886267820">"Zahtjev je otkazala aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+ <skip />
+ <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+ <skip />
</resources>
diff --git a/packages/CredentialManager/res/values-hu/strings.xml b/packages/CredentialManager/res/values-hu/strings.xml
index c25fa99..620e976 100644
--- a/packages/CredentialManager/res/values-hu/strings.xml
+++ b/packages/CredentialManager/res/values-hu/strings.xml
@@ -92,4 +92,8 @@
<string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Másik eszközről"</string>
<string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Másik eszköz használata"</string>
<string name="request_cancelled_by" msgid="3735222326886267820">"A kérelmet törölte a(z) <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+ <skip />
+ <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+ <skip />
</resources>
diff --git a/packages/CredentialManager/res/values-hy/strings.xml b/packages/CredentialManager/res/values-hy/strings.xml
index a6bda50..5423efe 100644
--- a/packages/CredentialManager/res/values-hy/strings.xml
+++ b/packages/CredentialManager/res/values-hy/strings.xml
@@ -92,4 +92,8 @@
<string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Մեկ այլ սարքից"</string>
<string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Օգտագործել այլ սարք"</string>
<string name="request_cancelled_by" msgid="3735222326886267820">"Հարցումը չեղարկվել է <xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածի կողմից"</string>
+ <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+ <skip />
+ <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+ <skip />
</resources>
diff --git a/packages/CredentialManager/res/values-in/strings.xml b/packages/CredentialManager/res/values-in/strings.xml
index d6bf946..df9d32d 100644
--- a/packages/CredentialManager/res/values-in/strings.xml
+++ b/packages/CredentialManager/res/values-in/strings.xml
@@ -92,4 +92,8 @@
<string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Dari perangkat lain"</string>
<string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Gunakan perangkat lain"</string>
<string name="request_cancelled_by" msgid="3735222326886267820">"Permintaan dibatalkan oleh <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+ <skip />
+ <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+ <skip />
</resources>
diff --git a/packages/CredentialManager/res/values-is/strings.xml b/packages/CredentialManager/res/values-is/strings.xml
index 76a869f..ba836f9 100644
--- a/packages/CredentialManager/res/values-is/strings.xml
+++ b/packages/CredentialManager/res/values-is/strings.xml
@@ -92,4 +92,8 @@
<string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Úr öðru tæki"</string>
<string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Nota annað tæki"</string>
<string name="request_cancelled_by" msgid="3735222326886267820">"<xliff:g id="APP_NAME">%1$s</xliff:g> hætti við beiðnina"</string>
+ <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+ <skip />
+ <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+ <skip />
</resources>
diff --git a/packages/CredentialManager/res/values-it/strings.xml b/packages/CredentialManager/res/values-it/strings.xml
index c5fd89c..d16d11f 100644
--- a/packages/CredentialManager/res/values-it/strings.xml
+++ b/packages/CredentialManager/res/values-it/strings.xml
@@ -92,4 +92,8 @@
<string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Da un altro dispositivo"</string>
<string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Usa un dispositivo diverso"</string>
<string name="request_cancelled_by" msgid="3735222326886267820">"Richiesta annullata da <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+ <skip />
+ <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+ <skip />
</resources>
diff --git a/packages/CredentialManager/res/values-iw/strings.xml b/packages/CredentialManager/res/values-iw/strings.xml
index 0643568..a9b01e1 100644
--- a/packages/CredentialManager/res/values-iw/strings.xml
+++ b/packages/CredentialManager/res/values-iw/strings.xml
@@ -92,4 +92,8 @@
<string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"ממכשיר אחר"</string>
<string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"צריך להשתמש במכשיר אחר"</string>
<string name="request_cancelled_by" msgid="3735222326886267820">"האפליקציה <xliff:g id="APP_NAME">%1$s</xliff:g> ביטלה את הבקשה"</string>
+ <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+ <skip />
+ <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+ <skip />
</resources>
diff --git a/packages/CredentialManager/res/values-ja/strings.xml b/packages/CredentialManager/res/values-ja/strings.xml
index afbff90..b452ec3 100644
--- a/packages/CredentialManager/res/values-ja/strings.xml
+++ b/packages/CredentialManager/res/values-ja/strings.xml
@@ -92,4 +92,8 @@
<string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"別のデバイスを使う"</string>
<string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"別のデバイスを使用"</string>
<string name="request_cancelled_by" msgid="3735222326886267820">"<xliff:g id="APP_NAME">%1$s</xliff:g> がリクエストをキャンセルしました"</string>
+ <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+ <skip />
+ <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+ <skip />
</resources>
diff --git a/packages/CredentialManager/res/values-ka/strings.xml b/packages/CredentialManager/res/values-ka/strings.xml
index 8125ec6..30479335 100644
--- a/packages/CredentialManager/res/values-ka/strings.xml
+++ b/packages/CredentialManager/res/values-ka/strings.xml
@@ -92,4 +92,8 @@
<string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"სხვა მოწყობილობიდან"</string>
<string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"გამოიყენეთ სხვა მოწყობილობა"</string>
<string name="request_cancelled_by" msgid="3735222326886267820">"თხოვნა გაუქმებულია <xliff:g id="APP_NAME">%1$s</xliff:g>-ის მიერ"</string>
+ <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+ <skip />
+ <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+ <skip />
</resources>
diff --git a/packages/CredentialManager/res/values-kk/strings.xml b/packages/CredentialManager/res/values-kk/strings.xml
index cb68444..891a600 100644
--- a/packages/CredentialManager/res/values-kk/strings.xml
+++ b/packages/CredentialManager/res/values-kk/strings.xml
@@ -92,4 +92,8 @@
<string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Басқа құрылғыдан жасау"</string>
<string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Басқа құрылғыны пайдалану"</string>
<string name="request_cancelled_by" msgid="3735222326886267820">"<xliff:g id="APP_NAME">%1$s</xliff:g> қолданбасы сұрауды тоқтатты."</string>
+ <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+ <skip />
+ <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+ <skip />
</resources>
diff --git a/packages/CredentialManager/res/values-km/strings.xml b/packages/CredentialManager/res/values-km/strings.xml
index d361ad9..d6fc505 100644
--- a/packages/CredentialManager/res/values-km/strings.xml
+++ b/packages/CredentialManager/res/values-km/strings.xml
@@ -92,4 +92,8 @@
<string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"ពីឧបករណ៍ផ្សេងទៀត"</string>
<string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"ប្រើឧបករណ៍ផ្សេង"</string>
<string name="request_cancelled_by" msgid="3735222326886267820">"បានបោះបង់សំណើដោយ <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+ <skip />
+ <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+ <skip />
</resources>
diff --git a/packages/CredentialManager/res/values-kn/strings.xml b/packages/CredentialManager/res/values-kn/strings.xml
index 7447ab6..ff38e19 100644
--- a/packages/CredentialManager/res/values-kn/strings.xml
+++ b/packages/CredentialManager/res/values-kn/strings.xml
@@ -92,4 +92,8 @@
<string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"ಮತ್ತೊಂದು ಸಾಧನದಿಂದ"</string>
<string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"ಬೇರೆ ಸಾಧನವನ್ನು ಬಳಸಿ"</string>
<string name="request_cancelled_by" msgid="3735222326886267820">"<xliff:g id="APP_NAME">%1$s</xliff:g> ನಿಂದ ವಿನಂತಿಯನ್ನು ರದ್ದುಗೊಳಿಸಲಾಗಿದೆ"</string>
+ <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+ <skip />
+ <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+ <skip />
</resources>
diff --git a/packages/CredentialManager/res/values-ko/strings.xml b/packages/CredentialManager/res/values-ko/strings.xml
index 07a7fbc..557c3ef 100644
--- a/packages/CredentialManager/res/values-ko/strings.xml
+++ b/packages/CredentialManager/res/values-ko/strings.xml
@@ -92,4 +92,8 @@
<string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"다른 기기에서"</string>
<string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"다른 기기 사용"</string>
<string name="request_cancelled_by" msgid="3735222326886267820">"<xliff:g id="APP_NAME">%1$s</xliff:g>에 의해 요청이 취소됨"</string>
+ <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+ <skip />
+ <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+ <skip />
</resources>
diff --git a/packages/CredentialManager/res/values-ky/strings.xml b/packages/CredentialManager/res/values-ky/strings.xml
index e2de2ef..4bc96b1d 100644
--- a/packages/CredentialManager/res/values-ky/strings.xml
+++ b/packages/CredentialManager/res/values-ky/strings.xml
@@ -92,4 +92,8 @@
<string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Башка түзмөктөн"</string>
<string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Башка түзмөктү колдонуу"</string>
<string name="request_cancelled_by" msgid="3735222326886267820">"Сурамды <xliff:g id="APP_NAME">%1$s</xliff:g> жокко чыгарды"</string>
+ <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+ <skip />
+ <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+ <skip />
</resources>
diff --git a/packages/CredentialManager/res/values-lo/strings.xml b/packages/CredentialManager/res/values-lo/strings.xml
index 3b2e2aa..ce103e0 100644
--- a/packages/CredentialManager/res/values-lo/strings.xml
+++ b/packages/CredentialManager/res/values-lo/strings.xml
@@ -92,4 +92,8 @@
<string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"ຈາກອຸປະກອນອື່ນ"</string>
<string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"ໃຊ້ອຸປະກອນອື່ນ"</string>
<string name="request_cancelled_by" msgid="3735222326886267820">"ການຮ້ອງຂໍຖືກຍົກເລີກໂດຍ <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+ <skip />
+ <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+ <skip />
</resources>
diff --git a/packages/CredentialManager/res/values-lt/strings.xml b/packages/CredentialManager/res/values-lt/strings.xml
index c3b941b..af27824 100644
--- a/packages/CredentialManager/res/values-lt/strings.xml
+++ b/packages/CredentialManager/res/values-lt/strings.xml
@@ -92,4 +92,8 @@
<string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Naudojant kitą įrenginį"</string>
<string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Naudoti kitą įrenginį"</string>
<string name="request_cancelled_by" msgid="3735222326886267820">"Užklausą atšaukė „<xliff:g id="APP_NAME">%1$s</xliff:g>“"</string>
+ <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+ <skip />
+ <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+ <skip />
</resources>
diff --git a/packages/CredentialManager/res/values-lv/strings.xml b/packages/CredentialManager/res/values-lv/strings.xml
index 27115ca..532ac5e 100644
--- a/packages/CredentialManager/res/values-lv/strings.xml
+++ b/packages/CredentialManager/res/values-lv/strings.xml
@@ -92,4 +92,8 @@
<string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"No citas ierīces"</string>
<string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Izmantot citu ierīci"</string>
<string name="request_cancelled_by" msgid="3735222326886267820">"<xliff:g id="APP_NAME">%1$s</xliff:g> atcēla pieprasījumu"</string>
+ <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+ <skip />
+ <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+ <skip />
</resources>
diff --git a/packages/CredentialManager/res/values-mk/strings.xml b/packages/CredentialManager/res/values-mk/strings.xml
index 1f456bf..ec9ebef 100644
--- a/packages/CredentialManager/res/values-mk/strings.xml
+++ b/packages/CredentialManager/res/values-mk/strings.xml
@@ -92,4 +92,8 @@
<string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Од друг уред"</string>
<string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Употребете друг уред"</string>
<string name="request_cancelled_by" msgid="3735222326886267820">"Барањето е откажано од <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+ <skip />
+ <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+ <skip />
</resources>
diff --git a/packages/CredentialManager/res/values-ml/strings.xml b/packages/CredentialManager/res/values-ml/strings.xml
index 07fea38..16ef8c8 100644
--- a/packages/CredentialManager/res/values-ml/strings.xml
+++ b/packages/CredentialManager/res/values-ml/strings.xml
@@ -92,4 +92,8 @@
<string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"മറ്റൊരു ഉപകരണത്തിൽ നിന്ന്"</string>
<string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"മറ്റൊരു ഉപകരണം ഉപയോഗിക്കുക"</string>
<string name="request_cancelled_by" msgid="3735222326886267820">"അഭ്യർത്ഥന <xliff:g id="APP_NAME">%1$s</xliff:g> റദ്ദാക്കി"</string>
+ <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+ <skip />
+ <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+ <skip />
</resources>
diff --git a/packages/CredentialManager/res/values-mn/strings.xml b/packages/CredentialManager/res/values-mn/strings.xml
index e37155a..4a5a8eea 100644
--- a/packages/CredentialManager/res/values-mn/strings.xml
+++ b/packages/CredentialManager/res/values-mn/strings.xml
@@ -92,4 +92,8 @@
<string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Өөр төхөөрөмжөөс"</string>
<string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Өөр төхөөрөмж ашиглах"</string>
<string name="request_cancelled_by" msgid="3735222326886267820">"Хүсэлтийг <xliff:g id="APP_NAME">%1$s</xliff:g> цуцалсан"</string>
+ <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+ <skip />
+ <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+ <skip />
</resources>
diff --git a/packages/CredentialManager/res/values-mr/strings.xml b/packages/CredentialManager/res/values-mr/strings.xml
index ceba101..6a76b02 100644
--- a/packages/CredentialManager/res/values-mr/strings.xml
+++ b/packages/CredentialManager/res/values-mr/strings.xml
@@ -92,4 +92,8 @@
<string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"दुसऱ्या डिव्हाइस वरून"</string>
<string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"वेगळे डिव्हाइस वापरा"</string>
<string name="request_cancelled_by" msgid="3735222326886267820">"<xliff:g id="APP_NAME">%1$s</xliff:g> ने विनंती रद्द केली आहे"</string>
+ <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+ <skip />
+ <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+ <skip />
</resources>
diff --git a/packages/CredentialManager/res/values-ms/strings.xml b/packages/CredentialManager/res/values-ms/strings.xml
index b933f3e..f759eed 100644
--- a/packages/CredentialManager/res/values-ms/strings.xml
+++ b/packages/CredentialManager/res/values-ms/strings.xml
@@ -92,4 +92,8 @@
<string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Daripada peranti lain"</string>
<string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Gunakan peranti yang lain"</string>
<string name="request_cancelled_by" msgid="3735222326886267820">"Permintaan dibatalkan oleh <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+ <skip />
+ <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+ <skip />
</resources>
diff --git a/packages/CredentialManager/res/values-my/strings.xml b/packages/CredentialManager/res/values-my/strings.xml
index c359ce1..9c15226 100644
--- a/packages/CredentialManager/res/values-my/strings.xml
+++ b/packages/CredentialManager/res/values-my/strings.xml
@@ -92,4 +92,8 @@
<string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"စက်နောက်တစ်ခုမှ"</string>
<string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"အခြားစက်သုံးရန်"</string>
<string name="request_cancelled_by" msgid="3735222326886267820">"တောင်းဆိုချက်ကို <xliff:g id="APP_NAME">%1$s</xliff:g> က ပယ်ဖျက်လိုက်သည်"</string>
+ <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+ <skip />
+ <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+ <skip />
</resources>
diff --git a/packages/CredentialManager/res/values-nb/strings.xml b/packages/CredentialManager/res/values-nb/strings.xml
index 7f63f10..327bc7f 100644
--- a/packages/CredentialManager/res/values-nb/strings.xml
+++ b/packages/CredentialManager/res/values-nb/strings.xml
@@ -92,4 +92,8 @@
<string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Fra en annen enhet"</string>
<string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Bruk en annen enhet"</string>
<string name="request_cancelled_by" msgid="3735222326886267820">"Forespørselen er kansellert av <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+ <skip />
+ <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+ <skip />
</resources>
diff --git a/packages/CredentialManager/res/values-ne/strings.xml b/packages/CredentialManager/res/values-ne/strings.xml
index 042ed62..044853a 100644
--- a/packages/CredentialManager/res/values-ne/strings.xml
+++ b/packages/CredentialManager/res/values-ne/strings.xml
@@ -92,4 +92,8 @@
<string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"अर्को डिभाइसका लागि"</string>
<string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"अर्कै डिभाइस प्रयोग गरी हेर्नुहोस्"</string>
<string name="request_cancelled_by" msgid="3735222326886267820">"<xliff:g id="APP_NAME">%1$s</xliff:g> ले अनुरोध रद्द गरेको छ"</string>
+ <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+ <skip />
+ <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+ <skip />
</resources>
diff --git a/packages/CredentialManager/res/values-nl/strings.xml b/packages/CredentialManager/res/values-nl/strings.xml
index 68f95a7..8386995 100644
--- a/packages/CredentialManager/res/values-nl/strings.xml
+++ b/packages/CredentialManager/res/values-nl/strings.xml
@@ -92,4 +92,8 @@
<string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Via een ander apparaat"</string>
<string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Een ander apparaat gebruiken"</string>
<string name="request_cancelled_by" msgid="3735222326886267820">"Verzoek geannuleerd door <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+ <skip />
+ <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+ <skip />
</resources>
diff --git a/packages/CredentialManager/res/values-or/strings.xml b/packages/CredentialManager/res/values-or/strings.xml
index 150ef0b..9f305ab 100644
--- a/packages/CredentialManager/res/values-or/strings.xml
+++ b/packages/CredentialManager/res/values-or/strings.xml
@@ -92,4 +92,8 @@
<string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"ଅନ୍ୟ ଏକ ଡିଭାଇସରୁ"</string>
<string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"ଏକ ଭିନ୍ନ ଡିଭାଇସ ବ୍ୟବହାର କରନ୍ତୁ"</string>
<string name="request_cancelled_by" msgid="3735222326886267820">"<xliff:g id="APP_NAME">%1$s</xliff:g> ଦ୍ୱାରା ଅନୁରୋଧ ବାତିଲ ହୋଇଛି"</string>
+ <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+ <skip />
+ <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+ <skip />
</resources>
diff --git a/packages/CredentialManager/res/values-pa/strings.xml b/packages/CredentialManager/res/values-pa/strings.xml
index 10ff1ad..b90ae5e 100644
--- a/packages/CredentialManager/res/values-pa/strings.xml
+++ b/packages/CredentialManager/res/values-pa/strings.xml
@@ -92,4 +92,8 @@
<string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"ਹੋਰ ਡੀਵਾਈਸ ਤੋਂ"</string>
<string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"ਵੱਖਰੇ ਡੀਵਾਈਸ ਦੀ ਵਰਤੋਂ ਕਰੋ"</string>
<string name="request_cancelled_by" msgid="3735222326886267820">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਵੱਲੋਂ ਬੇਨਤੀ ਰੱਦ ਕੀਤੀ ਗਈ"</string>
+ <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+ <skip />
+ <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+ <skip />
</resources>
diff --git a/packages/CredentialManager/res/values-pl/strings.xml b/packages/CredentialManager/res/values-pl/strings.xml
index be60af5..6966d21 100644
--- a/packages/CredentialManager/res/values-pl/strings.xml
+++ b/packages/CredentialManager/res/values-pl/strings.xml
@@ -92,4 +92,8 @@
<string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Na innym urządzeniu"</string>
<string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Użyj innego urządzenia"</string>
<string name="request_cancelled_by" msgid="3735222326886267820">"Żądanie anulowane przez aplikację <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+ <skip />
+ <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+ <skip />
</resources>
diff --git a/packages/CredentialManager/res/values-pt-rBR/strings.xml b/packages/CredentialManager/res/values-pt-rBR/strings.xml
index 93459e6..79da371 100644
--- a/packages/CredentialManager/res/values-pt-rBR/strings.xml
+++ b/packages/CredentialManager/res/values-pt-rBR/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="4539824758261855508">"Gerenciador de credenciais"</string>
+ <string name="app_name" msgid="4539824758261855508">"Credential Manager"</string>
<string name="string_cancel" msgid="6369133483981306063">"Cancelar"</string>
<string name="string_continue" msgid="1346732695941131882">"Continuar"</string>
<string name="string_more_options" msgid="2763852250269945472">"Salvar de outra forma"</string>
@@ -92,4 +92,8 @@
<string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"De outro dispositivo"</string>
<string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Usar um dispositivo diferente"</string>
<string name="request_cancelled_by" msgid="3735222326886267820">"Solicitação cancelada por <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+ <skip />
+ <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+ <skip />
</resources>
diff --git a/packages/CredentialManager/res/values-pt-rPT/strings.xml b/packages/CredentialManager/res/values-pt-rPT/strings.xml
index 27b84aa..208b475 100644
--- a/packages/CredentialManager/res/values-pt-rPT/strings.xml
+++ b/packages/CredentialManager/res/values-pt-rPT/strings.xml
@@ -92,4 +92,8 @@
<string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"De outro dispositivo"</string>
<string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Use um dispositivo diferente"</string>
<string name="request_cancelled_by" msgid="3735222326886267820">"Pedido cancelado pela app <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+ <skip />
+ <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+ <skip />
</resources>
diff --git a/packages/CredentialManager/res/values-pt/strings.xml b/packages/CredentialManager/res/values-pt/strings.xml
index 93459e6..79da371 100644
--- a/packages/CredentialManager/res/values-pt/strings.xml
+++ b/packages/CredentialManager/res/values-pt/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_name" msgid="4539824758261855508">"Gerenciador de credenciais"</string>
+ <string name="app_name" msgid="4539824758261855508">"Credential Manager"</string>
<string name="string_cancel" msgid="6369133483981306063">"Cancelar"</string>
<string name="string_continue" msgid="1346732695941131882">"Continuar"</string>
<string name="string_more_options" msgid="2763852250269945472">"Salvar de outra forma"</string>
@@ -92,4 +92,8 @@
<string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"De outro dispositivo"</string>
<string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Usar um dispositivo diferente"</string>
<string name="request_cancelled_by" msgid="3735222326886267820">"Solicitação cancelada por <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+ <skip />
+ <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+ <skip />
</resources>
diff --git a/packages/CredentialManager/res/values-ro/strings.xml b/packages/CredentialManager/res/values-ro/strings.xml
index 5292eca..8984cf2 100644
--- a/packages/CredentialManager/res/values-ro/strings.xml
+++ b/packages/CredentialManager/res/values-ro/strings.xml
@@ -92,4 +92,8 @@
<string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"De pe alt dispozitiv"</string>
<string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Folosește alt dispozitiv"</string>
<string name="request_cancelled_by" msgid="3735222326886267820">"Solicitare anulată de <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+ <skip />
+ <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+ <skip />
</resources>
diff --git a/packages/CredentialManager/res/values-ru/strings.xml b/packages/CredentialManager/res/values-ru/strings.xml
index 99d2d7cc..0f99831 100644
--- a/packages/CredentialManager/res/values-ru/strings.xml
+++ b/packages/CredentialManager/res/values-ru/strings.xml
@@ -92,4 +92,8 @@
<string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"С другого устройства"</string>
<string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Использовать другое устройство"</string>
<string name="request_cancelled_by" msgid="3735222326886267820">"Приложение \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" отменило запрос."</string>
+ <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+ <skip />
+ <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+ <skip />
</resources>
diff --git a/packages/CredentialManager/res/values-si/strings.xml b/packages/CredentialManager/res/values-si/strings.xml
index 79eaa13..9969a0c 100644
--- a/packages/CredentialManager/res/values-si/strings.xml
+++ b/packages/CredentialManager/res/values-si/strings.xml
@@ -92,4 +92,8 @@
<string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"වෙනත් උපාංගයකින්"</string>
<string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"වෙනස් උපාංගයක් භාවිතා කරන්න"</string>
<string name="request_cancelled_by" msgid="3735222326886267820">"<xliff:g id="APP_NAME">%1$s</xliff:g> විසින් ඉල්ලීම අවලංගු කරන ලදී"</string>
+ <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+ <skip />
+ <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+ <skip />
</resources>
diff --git a/packages/CredentialManager/res/values-sk/strings.xml b/packages/CredentialManager/res/values-sk/strings.xml
index 90805a4..f91f546 100644
--- a/packages/CredentialManager/res/values-sk/strings.xml
+++ b/packages/CredentialManager/res/values-sk/strings.xml
@@ -92,4 +92,8 @@
<string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Z iného zariadenia"</string>
<string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Použiť iné zariadenie"</string>
<string name="request_cancelled_by" msgid="3735222326886267820">"Požiadavku zrušila aplikácia <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+ <skip />
+ <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+ <skip />
</resources>
diff --git a/packages/CredentialManager/res/values-sl/strings.xml b/packages/CredentialManager/res/values-sl/strings.xml
index 16ba222..196b0aa 100644
--- a/packages/CredentialManager/res/values-sl/strings.xml
+++ b/packages/CredentialManager/res/values-sl/strings.xml
@@ -92,4 +92,8 @@
<string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Iz druge naprave"</string>
<string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Uporaba druge naprave"</string>
<string name="request_cancelled_by" msgid="3735222326886267820">"Zahtevo je preklicala aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+ <skip />
+ <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+ <skip />
</resources>
diff --git a/packages/CredentialManager/res/values-sq/strings.xml b/packages/CredentialManager/res/values-sq/strings.xml
index 391c511..5fceff5 100644
--- a/packages/CredentialManager/res/values-sq/strings.xml
+++ b/packages/CredentialManager/res/values-sq/strings.xml
@@ -92,4 +92,8 @@
<string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Nga një pajisje tjetër"</string>
<string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Përdor një pajisje tjetër"</string>
<string name="request_cancelled_by" msgid="3735222326886267820">"Kërkesa u anulua nga <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+ <skip />
+ <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+ <skip />
</resources>
diff --git a/packages/CredentialManager/res/values-sr/strings.xml b/packages/CredentialManager/res/values-sr/strings.xml
index b83c698..d721a4b 100644
--- a/packages/CredentialManager/res/values-sr/strings.xml
+++ b/packages/CredentialManager/res/values-sr/strings.xml
@@ -92,4 +92,8 @@
<string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Са другог уређаја"</string>
<string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Користи други уређај"</string>
<string name="request_cancelled_by" msgid="3735222326886267820">"Захтве је отказала апликација <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+ <skip />
+ <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+ <skip />
</resources>
diff --git a/packages/CredentialManager/res/values-sv/strings.xml b/packages/CredentialManager/res/values-sv/strings.xml
index 65319b0..d3099cbc4 100644
--- a/packages/CredentialManager/res/values-sv/strings.xml
+++ b/packages/CredentialManager/res/values-sv/strings.xml
@@ -92,4 +92,8 @@
<string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Via en annan enhet"</string>
<string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Använd en annan enhet"</string>
<string name="request_cancelled_by" msgid="3735222326886267820">"Begäran avbruten av <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+ <skip />
+ <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+ <skip />
</resources>
diff --git a/packages/CredentialManager/res/values-sw/strings.xml b/packages/CredentialManager/res/values-sw/strings.xml
index ffb4fa0..1e31128 100644
--- a/packages/CredentialManager/res/values-sw/strings.xml
+++ b/packages/CredentialManager/res/values-sw/strings.xml
@@ -92,4 +92,8 @@
<string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Kutoka kwenye kifaa kingine"</string>
<string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Tumia kifaa tofauti"</string>
<string name="request_cancelled_by" msgid="3735222326886267820">"Ombi lilighairiwa na <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+ <skip />
+ <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+ <skip />
</resources>
diff --git a/packages/CredentialManager/res/values-ta/strings.xml b/packages/CredentialManager/res/values-ta/strings.xml
index 750b67d..1d4e55a 100644
--- a/packages/CredentialManager/res/values-ta/strings.xml
+++ b/packages/CredentialManager/res/values-ta/strings.xml
@@ -92,4 +92,8 @@
<string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"மற்றொரு சாதனத்திலிருந்து பயன்படுத்து"</string>
<string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"வேறு சாதனத்தைப் பயன்படுத்து"</string>
<string name="request_cancelled_by" msgid="3735222326886267820">"<xliff:g id="APP_NAME">%1$s</xliff:g> ஆப்ஸால் கோரிக்கை ரத்துசெய்யப்பட்டது"</string>
+ <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+ <skip />
+ <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+ <skip />
</resources>
diff --git a/packages/CredentialManager/res/values-te/strings.xml b/packages/CredentialManager/res/values-te/strings.xml
index 064ee96..d546b66 100644
--- a/packages/CredentialManager/res/values-te/strings.xml
+++ b/packages/CredentialManager/res/values-te/strings.xml
@@ -92,4 +92,8 @@
<string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"మరొక పరికరం నుండి"</string>
<string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"వేరే పరికరాన్ని ఉపయోగించండి"</string>
<string name="request_cancelled_by" msgid="3735222326886267820">"<xliff:g id="APP_NAME">%1$s</xliff:g>, రిక్వెస్ట్ను రద్దు చేసింది"</string>
+ <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+ <skip />
+ <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+ <skip />
</resources>
diff --git a/packages/CredentialManager/res/values-th/strings.xml b/packages/CredentialManager/res/values-th/strings.xml
index 249bd88..7ebe82f 100644
--- a/packages/CredentialManager/res/values-th/strings.xml
+++ b/packages/CredentialManager/res/values-th/strings.xml
@@ -92,4 +92,8 @@
<string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"จากอุปกรณ์อื่น"</string>
<string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"ใช้อุปกรณ์อื่น"</string>
<string name="request_cancelled_by" msgid="3735222326886267820">"ยกเลิกคำขอแล้วโดย <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+ <skip />
+ <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+ <skip />
</resources>
diff --git a/packages/CredentialManager/res/values-tl/strings.xml b/packages/CredentialManager/res/values-tl/strings.xml
index e33f1bf..d069ffe 100644
--- a/packages/CredentialManager/res/values-tl/strings.xml
+++ b/packages/CredentialManager/res/values-tl/strings.xml
@@ -92,4 +92,8 @@
<string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Mula sa ibang device"</string>
<string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Gumamit ng ibang device"</string>
<string name="request_cancelled_by" msgid="3735222326886267820">"Kinansela ng <xliff:g id="APP_NAME">%1$s</xliff:g> ang kahilingan"</string>
+ <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+ <skip />
+ <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+ <skip />
</resources>
diff --git a/packages/CredentialManager/res/values-tr/strings.xml b/packages/CredentialManager/res/values-tr/strings.xml
index 4e4894c..718d7bd 100644
--- a/packages/CredentialManager/res/values-tr/strings.xml
+++ b/packages/CredentialManager/res/values-tr/strings.xml
@@ -92,4 +92,8 @@
<string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Başka bir cihazdan"</string>
<string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Farklı bir cihaz kullan"</string>
<string name="request_cancelled_by" msgid="3735222326886267820">"İstek, <xliff:g id="APP_NAME">%1$s</xliff:g> tarafından iptal edildi"</string>
+ <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+ <skip />
+ <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+ <skip />
</resources>
diff --git a/packages/CredentialManager/res/values-uk/strings.xml b/packages/CredentialManager/res/values-uk/strings.xml
index 78a5a5b..c23933a 100644
--- a/packages/CredentialManager/res/values-uk/strings.xml
+++ b/packages/CredentialManager/res/values-uk/strings.xml
@@ -92,4 +92,8 @@
<string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"З іншого пристрою"</string>
<string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Використовувати інший пристрій"</string>
<string name="request_cancelled_by" msgid="3735222326886267820">"Додаток <xliff:g id="APP_NAME">%1$s</xliff:g> скасував запит"</string>
+ <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+ <skip />
+ <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+ <skip />
</resources>
diff --git a/packages/CredentialManager/res/values-ur/strings.xml b/packages/CredentialManager/res/values-ur/strings.xml
index d3d5d85..9bb1662 100644
--- a/packages/CredentialManager/res/values-ur/strings.xml
+++ b/packages/CredentialManager/res/values-ur/strings.xml
@@ -92,4 +92,8 @@
<string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"دوسرے آلے سے"</string>
<string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"ایک مختلف آلہ استعمال کریں"</string>
<string name="request_cancelled_by" msgid="3735222326886267820">"<xliff:g id="APP_NAME">%1$s</xliff:g> نے درخواست منسوخ کر دی"</string>
+ <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+ <skip />
+ <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+ <skip />
</resources>
diff --git a/packages/CredentialManager/res/values-uz/strings.xml b/packages/CredentialManager/res/values-uz/strings.xml
index a0785b6..90264e9 100644
--- a/packages/CredentialManager/res/values-uz/strings.xml
+++ b/packages/CredentialManager/res/values-uz/strings.xml
@@ -92,4 +92,8 @@
<string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Boshqa qurilmada"</string>
<string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Boshqa qurilmadan foydalanish"</string>
<string name="request_cancelled_by" msgid="3735222326886267820">"Soʻrovni <xliff:g id="APP_NAME">%1$s</xliff:g> bekor qilgan"</string>
+ <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+ <skip />
+ <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+ <skip />
</resources>
diff --git a/packages/CredentialManager/res/values-vi/strings.xml b/packages/CredentialManager/res/values-vi/strings.xml
index 0e17025..c6f897e 100644
--- a/packages/CredentialManager/res/values-vi/strings.xml
+++ b/packages/CredentialManager/res/values-vi/strings.xml
@@ -92,4 +92,8 @@
<string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Từ một thiết bị khác"</string>
<string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Dùng thiết bị khác"</string>
<string name="request_cancelled_by" msgid="3735222326886267820">"<xliff:g id="APP_NAME">%1$s</xliff:g> đã huỷ yêu cầu"</string>
+ <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+ <skip />
+ <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+ <skip />
</resources>
diff --git a/packages/CredentialManager/res/values-zh-rCN/strings.xml b/packages/CredentialManager/res/values-zh-rCN/strings.xml
index 495abe6..f5bb10f 100644
--- a/packages/CredentialManager/res/values-zh-rCN/strings.xml
+++ b/packages/CredentialManager/res/values-zh-rCN/strings.xml
@@ -92,4 +92,8 @@
<string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"通过另一台设备"</string>
<string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"使用其他设备"</string>
<string name="request_cancelled_by" msgid="3735222326886267820">"<xliff:g id="APP_NAME">%1$s</xliff:g>已取消请求"</string>
+ <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+ <skip />
+ <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+ <skip />
</resources>
diff --git a/packages/CredentialManager/res/values-zh-rHK/strings.xml b/packages/CredentialManager/res/values-zh-rHK/strings.xml
index f786254..ab54793 100644
--- a/packages/CredentialManager/res/values-zh-rHK/strings.xml
+++ b/packages/CredentialManager/res/values-zh-rHK/strings.xml
@@ -92,4 +92,8 @@
<string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"透過其他裝置"</string>
<string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"使用其他裝置"</string>
<string name="request_cancelled_by" msgid="3735222326886267820">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」已取消要求"</string>
+ <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+ <skip />
+ <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+ <skip />
</resources>
diff --git a/packages/CredentialManager/res/values-zh-rTW/strings.xml b/packages/CredentialManager/res/values-zh-rTW/strings.xml
index c09bf86..f8f8eec 100644
--- a/packages/CredentialManager/res/values-zh-rTW/strings.xml
+++ b/packages/CredentialManager/res/values-zh-rTW/strings.xml
@@ -92,4 +92,8 @@
<string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"透過其他裝置"</string>
<string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"使用其他裝置"</string>
<string name="request_cancelled_by" msgid="3735222326886267820">"要求已由 <xliff:g id="APP_NAME">%1$s</xliff:g> 取消"</string>
+ <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+ <skip />
+ <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+ <skip />
</resources>
diff --git a/packages/CredentialManager/res/values-zu/strings.xml b/packages/CredentialManager/res/values-zu/strings.xml
index 91f93e2..85fe60a 100644
--- a/packages/CredentialManager/res/values-zu/strings.xml
+++ b/packages/CredentialManager/res/values-zu/strings.xml
@@ -92,4 +92,8 @@
<string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Kusukela kwenye idivayisi"</string>
<string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Sebenzisa idivayisi ehlukile"</string>
<string name="request_cancelled_by" msgid="3735222326886267820">"Isicelo sikhanselwe yi-<xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <!-- no translation found for dropdown_presentation_more_sign_in_options_text (1693727354272417902) -->
+ <skip />
+ <!-- no translation found for provider_icon_content_description (4023359912607637248) -->
+ <skip />
</resources>
diff --git a/packages/CredentialManager/shared/src/com/android/credentialmanager/IntentParser.kt b/packages/CredentialManager/shared/src/com/android/credentialmanager/IntentParser.kt
index 325d3f8..0fa248d 100644
--- a/packages/CredentialManager/shared/src/com/android/credentialmanager/IntentParser.kt
+++ b/packages/CredentialManager/shared/src/com/android/credentialmanager/IntentParser.kt
@@ -19,7 +19,7 @@
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
-import android.credentials.ui.RequestInfo
+import android.credentials.selection.RequestInfo
import android.util.Log
import com.android.credentialmanager.ktx.appLabel
import com.android.credentialmanager.ktx.cancelUiRequest
diff --git a/packages/CredentialManager/shared/src/com/android/credentialmanager/client/CredentialManagerClient.kt b/packages/CredentialManager/shared/src/com/android/credentialmanager/client/CredentialManagerClient.kt
index 49387cf..3fbff37 100644
--- a/packages/CredentialManager/shared/src/com/android/credentialmanager/client/CredentialManagerClient.kt
+++ b/packages/CredentialManager/shared/src/com/android/credentialmanager/client/CredentialManagerClient.kt
@@ -17,8 +17,8 @@
package com.android.credentialmanager.client
import android.content.Intent
-import android.credentials.ui.BaseDialogResult
-import android.credentials.ui.UserSelectionDialogResult
+import android.credentials.selection.BaseDialogResult
+import android.credentials.selection.UserSelectionDialogResult
import com.android.credentialmanager.model.Request
import kotlinx.coroutines.flow.StateFlow
diff --git a/packages/CredentialManager/shared/src/com/android/credentialmanager/client/impl/CredentialManagerClientImpl.kt b/packages/CredentialManager/shared/src/com/android/credentialmanager/client/impl/CredentialManagerClientImpl.kt
index 3ef65b0..ec1f052 100644
--- a/packages/CredentialManager/shared/src/com/android/credentialmanager/client/impl/CredentialManagerClientImpl.kt
+++ b/packages/CredentialManager/shared/src/com/android/credentialmanager/client/impl/CredentialManagerClientImpl.kt
@@ -18,8 +18,8 @@
import android.content.Context
import android.content.Intent
-import android.credentials.ui.BaseDialogResult
-import android.credentials.ui.UserSelectionDialogResult
+import android.credentials.selection.BaseDialogResult
+import android.credentials.selection.UserSelectionDialogResult
import android.os.Bundle
import android.util.Log
import com.android.credentialmanager.TAG
diff --git a/packages/CredentialManager/shared/src/com/android/credentialmanager/ktx/CredentialKtx.kt b/packages/CredentialManager/shared/src/com/android/credentialmanager/ktx/CredentialKtx.kt
index f063074..a5f227a 100644
--- a/packages/CredentialManager/shared/src/com/android/credentialmanager/ktx/CredentialKtx.kt
+++ b/packages/CredentialManager/shared/src/com/android/credentialmanager/ktx/CredentialKtx.kt
@@ -23,9 +23,9 @@
import android.content.pm.PackageManager
import android.credentials.Credential
import android.credentials.flags.Flags
-import android.credentials.ui.AuthenticationEntry
-import android.credentials.ui.Entry
-import android.credentials.ui.GetCredentialProviderData
+import android.credentials.selection.AuthenticationEntry
+import android.credentials.selection.Entry
+import android.credentials.selection.GetCredentialProviderData
import android.graphics.drawable.Drawable
import android.text.TextUtils
import android.util.Log
diff --git a/packages/CredentialManager/shared/src/com/android/credentialmanager/ktx/IntentKtx.kt b/packages/CredentialManager/shared/src/com/android/credentialmanager/ktx/IntentKtx.kt
index 3abdb6f..4155b03 100644
--- a/packages/CredentialManager/shared/src/com/android/credentialmanager/ktx/IntentKtx.kt
+++ b/packages/CredentialManager/shared/src/com/android/credentialmanager/ktx/IntentKtx.kt
@@ -17,12 +17,12 @@
package com.android.credentialmanager.ktx
import android.content.Intent
-import android.credentials.ui.CancelUiRequest
-import android.credentials.ui.Constants
-import android.credentials.ui.CreateCredentialProviderData
-import android.credentials.ui.GetCredentialProviderData
-import android.credentials.ui.ProviderData
-import android.credentials.ui.RequestInfo
+import android.credentials.selection.CancelUiRequest
+import android.credentials.selection.Constants
+import android.credentials.selection.CreateCredentialProviderData
+import android.credentials.selection.GetCredentialProviderData
+import android.credentials.selection.ProviderData
+import android.credentials.selection.RequestInfo
import android.os.ResultReceiver
val Intent.cancelUiRequest: CancelUiRequest?
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt b/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt
index c0d7149..6cafcf7 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt
@@ -18,16 +18,16 @@
import android.content.Context
import android.content.Intent
-import android.credentials.ui.CancelUiRequest
-import android.credentials.ui.Constants
-import android.credentials.ui.CreateCredentialProviderData
-import android.credentials.ui.GetCredentialProviderData
-import android.credentials.ui.DisabledProviderData
-import android.credentials.ui.ProviderData
-import android.credentials.ui.RequestInfo
-import android.credentials.ui.BaseDialogResult
-import android.credentials.ui.ProviderPendingIntentResponse
-import android.credentials.ui.UserSelectionDialogResult
+import android.credentials.selection.CancelUiRequest
+import android.credentials.selection.Constants
+import android.credentials.selection.CreateCredentialProviderData
+import android.credentials.selection.GetCredentialProviderData
+import android.credentials.selection.DisabledProviderData
+import android.credentials.selection.ProviderData
+import android.credentials.selection.RequestInfo
+import android.credentials.selection.BaseDialogResult
+import android.credentials.selection.ProviderPendingIntentResponse
+import android.credentials.selection.UserSelectionDialogResult
import android.os.IBinder
import android.os.Bundle
import android.os.ResultReceiver
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorActivity.kt b/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorActivity.kt
index f8ffc9e..fa975aa 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorActivity.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorActivity.kt
@@ -18,8 +18,8 @@
import android.app.Activity
import android.content.Intent
-import android.credentials.ui.BaseDialogResult
-import android.credentials.ui.RequestInfo
+import android.credentials.selection.BaseDialogResult
+import android.credentials.selection.RequestInfo
import android.net.Uri
import android.os.Bundle
import android.os.ResultReceiver
@@ -213,7 +213,7 @@
private fun onInitializationError(e: Exception, intent: Intent) {
Log.e(Constants.LOG_TAG, "Failed to show the credential selector; closing the activity", e)
val resultReceiver = intent.getParcelableExtra(
- android.credentials.ui.Constants.EXTRA_RESULT_RECEIVER,
+ android.credentials.selection.Constants.EXTRA_RESULT_RECEIVER,
ResultReceiver::class.java
)
val requestInfo = intent.extras?.getParcelable(
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt b/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt
index fc3970d..64595e2 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt
@@ -20,11 +20,11 @@
import android.content.Context
import android.content.pm.PackageInfo
import android.content.pm.PackageManager
-import android.credentials.ui.CreateCredentialProviderData
-import android.credentials.ui.DisabledProviderData
-import android.credentials.ui.Entry
-import android.credentials.ui.GetCredentialProviderData
-import android.credentials.ui.RequestInfo
+import android.credentials.selection.CreateCredentialProviderData
+import android.credentials.selection.DisabledProviderData
+import android.credentials.selection.Entry
+import android.credentials.selection.GetCredentialProviderData
+import android.credentials.selection.RequestInfo
import android.graphics.drawable.Drawable
import android.text.TextUtils
import android.util.Log
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt b/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt
index 985f322..1f1d236 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt
@@ -25,8 +25,8 @@
import android.credentials.GetCandidateCredentialsResponse
import android.credentials.GetCandidateCredentialsException
import android.credentials.CredentialOption
+import android.credentials.selection.GetCredentialProviderData
import android.graphics.drawable.Icon
-import android.credentials.ui.GetCredentialProviderData
import android.os.Bundle
import android.os.CancellationSignal
import android.os.OutcomeReceiver
@@ -51,7 +51,6 @@
import android.credentials.CredentialManager
import android.widget.RemoteViews
import androidx.autofill.inline.v1.InlineSuggestionUi
-import androidx.core.content.ContextCompat
import androidx.credentials.provider.CustomCredentialEntry
import androidx.credentials.provider.PasswordCredentialEntry
import androidx.credentials.provider.PublicKeyCredentialEntry
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/common/DialogType.kt b/packages/CredentialManager/src/com/android/credentialmanager/common/DialogType.kt
index f40dc7e..22a5ec1 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/common/DialogType.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/common/DialogType.kt
@@ -16,7 +16,7 @@
package com.android.credentialmanager.common
-import android.credentials.ui.RequestInfo
+import android.credentials.selection.RequestInfo
enum class DialogType {
CREATE_CREDENTIAL,
diff --git a/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/screens/single/password/SinglePasswordScreenViewModel.kt b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/screens/single/password/SinglePasswordScreenViewModel.kt
index 4f9fc46..c9c66b4 100644
--- a/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/screens/single/password/SinglePasswordScreenViewModel.kt
+++ b/packages/CredentialManager/wear/src/com/android/credentialmanager/ui/screens/single/password/SinglePasswordScreenViewModel.kt
@@ -17,8 +17,8 @@
package com.android.credentialmanager.ui.screens.single.password
import android.content.Intent
-import android.credentials.ui.ProviderPendingIntentResponse
-import android.credentials.ui.UserSelectionDialogResult
+import android.credentials.selection.ProviderPendingIntentResponse
+import android.credentials.selection.UserSelectionDialogResult
import androidx.activity.result.IntentSenderRequest
import androidx.annotation.MainThread
import androidx.lifecycle.ViewModel
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/CustomizedAppBar.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/CustomizedAppBar.kt
index 3a0e51b..4f61966 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/CustomizedAppBar.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/CustomizedAppBar.kt
@@ -64,6 +64,8 @@
import androidx.compose.ui.layout.onGloballyPositioned
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.semantics.clearAndSetSemantics
+import androidx.compose.ui.semantics.heading
+import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.Constraints
@@ -129,7 +131,8 @@
modifier = Modifier.padding(
start = SettingsDimension.itemPaddingAround,
end = SettingsDimension.itemPaddingEnd,
- ),
+ )
+ .semantics { heading() },
overflow = TextOverflow.Ellipsis,
maxLines = maxLines,
)
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/framework/common/BroadcastReceiverFlow.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/framework/common/BroadcastReceiverFlow.kt
index e099f11..0a424bc 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/framework/common/BroadcastReceiverFlow.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/framework/common/BroadcastReceiverFlow.kt
@@ -37,10 +37,11 @@
fun Context.broadcastReceiverFlow(intentFilter: IntentFilter): Flow<Intent> = callbackFlow {
val broadcastReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
+ Log.d(TAG, "onReceive: $intent")
trySend(intent)
}
}
- registerReceiver(broadcastReceiver, intentFilter, Context.RECEIVER_NOT_EXPORTED)
+ registerReceiver(broadcastReceiver, intentFilter, Context.RECEIVER_VISIBLE_TO_INSTANT_APPS)
awaitClose { unregisterReceiver(broadcastReceiver) }
}.catch { e ->
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/framework/common/BroadcastReceiverFlowTest.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/framework/common/BroadcastReceiverFlowTest.kt
index eef5225..772f925 100644
--- a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/framework/common/BroadcastReceiverFlowTest.kt
+++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/framework/common/BroadcastReceiverFlowTest.kt
@@ -43,7 +43,7 @@
private val context = mock<Context> {
on {
- registerReceiver(any(), eq(INTENT_FILTER), eq(Context.RECEIVER_NOT_EXPORTED))
+ registerReceiver(any(), eq(INTENT_FILTER), eq(Context.RECEIVER_VISIBLE_TO_INSTANT_APPS))
} doAnswer {
registeredBroadcastReceiver = it.arguments[0] as BroadcastReceiver
null
diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml
index e3a313c..fd2c076 100644
--- a/packages/SettingsLib/res/values-af/strings.xml
+++ b/packages/SettingsLib/res/values-af/strings.xml
@@ -154,8 +154,7 @@
<string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"Prenttoestel"</string>
<string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"Oorfoon"</string>
<string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"Randinvoertoestel"</string>
- <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
- <skip />
+ <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"Gehoortoestelle"</string>
<string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"Bluetooth"</string>
<string name="accessibility_wifi_off" msgid="1195445715254137155">"Wi-Fi af."</string>
<string name="accessibility_no_wifi" msgid="5297119459491085771">"Wi-Fi is ontkoppel."</string>
@@ -457,10 +456,8 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"Kleurregstelling kan nuttig wees wanneer jy die volgende wil doen:<br/> <ol> <li>&nbsp;Om kleure meer akkuraat te sien</li> <li>&nbsp;Om kleure te verwyder om jou te help fokus</li> </ol>"</string>
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"Geneutraliseer deur <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
- <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
- <skip />
- <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
- <skip />
+ <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> – Laaiproses is onderbreek om battery te beskerm"</string>
+ <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> – Kontroleer tans laaibykomstigheid"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"Ongeveer <xliff:g id="TIME_REMAINING">%1$s</xliff:g> oor"</string>
<string name="power_discharging_duration" msgid="1076561255466053220">"Ongeveer <xliff:g id="TIME_REMAINING">%1$s</xliff:g> oor (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
<string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Ongeveer <xliff:g id="TIME_REMAINING">%1$s</xliff:g> oor gegrond op jou gebruik"</string>
@@ -489,12 +486,10 @@
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Laai tans draadloos"</string>
<string name="battery_info_status_charging_dock" msgid="8573274094093364791">"Laai tans"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Laai nie"</string>
- <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
- <skip />
+ <string name="battery_info_status_not_charging" msgid="1103084691314264664">"Gekoppel, maar laai nie"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Gelaai"</string>
<string name="battery_info_status_full_charged" msgid="3536054261505567948">"Volgelaai"</string>
- <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
- <skip />
+ <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"Laai wag tans"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Beheer deur administrateur"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Beheer deur Beperkte Instellings"</string>
<string name="disabled" msgid="8017887509554714950">"Gedeaktiveer"</string>
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index ff220fa..5afd9dc 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -154,8 +154,7 @@
<string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"تصوير"</string>
<string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"السمّاعة"</string>
<string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"جهاز إدخال ملحق"</string>
- <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
- <skip />
+ <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"سماعات أذن طبية"</string>
<string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"بلوتوث"</string>
<string name="accessibility_wifi_off" msgid="1195445715254137155">"تم إيقاف Wi-Fi."</string>
<string name="accessibility_no_wifi" msgid="5297119459491085771">"تم قطع اتصال Wi-Fi."</string>
@@ -220,8 +219,8 @@
<item msgid="6946761421234586000">"400%"</item>
</string-array>
<string name="choose_profile" msgid="343803890897657450">"اختيار ملف شخصي"</string>
- <string name="category_personal" msgid="6236798763159385225">"التطبيقات الشخصية"</string>
- <string name="category_work" msgid="4014193632325996115">"تطبيقات العمل"</string>
+ <string name="category_personal" msgid="6236798763159385225">"الحسابات الشخصية"</string>
+ <string name="category_work" msgid="4014193632325996115">"حسابات العمل"</string>
<string name="category_private" msgid="4244892185452788977">"ملف شخصي"</string>
<string name="category_clone" msgid="1554511758987195974">"استنساخ"</string>
<string name="development_settings_title" msgid="140296922921597393">"خيارات المطورين"</string>
@@ -457,10 +456,8 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"يمكنك الاستفادة من ميزة \"تصحيح الألوان\" من أجل:<br/> <ol> <li>&nbsp;رؤية الألوان بدقة أكبر</li> <li>&nbsp;إزالة الألوان لمساعدتك على التركيز</li> </ol>"</string>
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"تم الاستبدال بـ <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
- <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
- <skip />
- <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
- <skip />
+ <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - الشحن معلَّق لحماية البطارية"</string>
+ <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - يجب فحص ملحق الشحن"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"يتبقى <xliff:g id="TIME_REMAINING">%1$s</xliff:g> تقريبًا."</string>
<string name="power_discharging_duration" msgid="1076561255466053220">"يتبقى <xliff:g id="TIME_REMAINING">%1$s</xliff:g> تقريبًا (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
<string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"يتبقى <xliff:g id="TIME_REMAINING">%1$s</xliff:g> تقريبًا، بناءً على استخدامك"</string>
@@ -489,12 +486,10 @@
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"جارٍ الشحن لاسلكيًا"</string>
<string name="battery_info_status_charging_dock" msgid="8573274094093364791">"جارٍ الشحن"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"لا يتم الشحن"</string>
- <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
- <skip />
+ <string name="battery_info_status_not_charging" msgid="1103084691314264664">"الجهاز متصل ولكن لا يتم شحنه"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"مشحونة"</string>
<string name="battery_info_status_full_charged" msgid="3536054261505567948">"البطارية مشحونة بالكامل."</string>
- <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
- <skip />
+ <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"الشحن معلَّق"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"إعدادات يتحكم فيها المشرف"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"يتحكّم فيه إعداد محظور"</string>
<string name="disabled" msgid="8017887509554714950">"غير مفعّل"</string>
diff --git a/packages/SettingsLib/res/values-az/strings.xml b/packages/SettingsLib/res/values-az/strings.xml
index 63154fc..0ee8b89 100644
--- a/packages/SettingsLib/res/values-az/strings.xml
+++ b/packages/SettingsLib/res/values-az/strings.xml
@@ -154,8 +154,7 @@
<string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"Şəkilləndirmə"</string>
<string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"Qulaqlıq"</string>
<string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"Daxiletmə periferiki"</string>
- <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
- <skip />
+ <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"Eşitmə aparatları"</string>
<string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"Bluetooth"</string>
<string name="accessibility_wifi_off" msgid="1195445715254137155">"Wifi sönülüdür."</string>
<string name="accessibility_no_wifi" msgid="5297119459491085771">"Wifi bağlantı kəsildi."</string>
@@ -457,10 +456,8 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"Rəng korreksiyası bunları etmək istədikdə faydalı ola bilər:<br/> <ol> <li>&nbsp;Rəngləri daha dəqiq görmək</li> <li>&nbsp;Fokuslanmaq üçün rəngləri ləğv etmək</li> </ol>"</string>
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> tərəfindən qəbul edilmir"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
- <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
- <skip />
- <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
- <skip />
+ <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - Batareyanı qorumaq üçün şarj gözlədilir"</string>
+ <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - Şarj aksesuarı yoxlanır"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"Təxminən <xliff:g id="TIME_REMAINING">%1$s</xliff:g> qalıb"</string>
<string name="power_discharging_duration" msgid="1076561255466053220">"Təxminən <xliff:g id="TIME_REMAINING">%1$s</xliff:g> qalıb (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
<string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"İstifadəyə əsasən təxminən <xliff:g id="TIME_REMAINING">%1$s</xliff:g> qalıb"</string>
@@ -489,12 +486,10 @@
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Simsiz şarj edilir"</string>
<string name="battery_info_status_charging_dock" msgid="8573274094093364791">"Şarj edilir"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Doldurulmur"</string>
- <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
- <skip />
+ <string name="battery_info_status_not_charging" msgid="1103084691314264664">"Qoşulub, amma şarj edilmir"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Şarj edilib"</string>
<string name="battery_info_status_full_charged" msgid="3536054261505567948">"Tam şarj edilib"</string>
- <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
- <skip />
+ <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"Şarj gözlədilir"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Admin tərəfindən nəzarət olunur"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Məhdudlaşdırılmış Ayar ilə nəzarət edilir"</string>
<string name="disabled" msgid="8017887509554714950">"Deaktiv"</string>
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
index 14f3883..0cf6887 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
@@ -154,8 +154,7 @@
<string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"Obrada slika"</string>
<string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"Slušalice"</string>
<string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"Periferni uređaj za unos"</string>
- <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
- <skip />
+ <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"Slušni aparati"</string>
<string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"Bluetooth"</string>
<string name="accessibility_wifi_off" msgid="1195445715254137155">"WiFi je isključen."</string>
<string name="accessibility_no_wifi" msgid="5297119459491085771">"WiFi veza je prekinuta."</string>
@@ -457,10 +456,8 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"Korekcija boja može da bude korisna kada želite:<br/> <ol> <li>&nbsp;Preciznije da vidite boje</li> <li>&nbsp;Da uklonite boje kako biste se fokusirali</li> </ol>"</string>
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"Zamenjuje ga <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g>–<xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
- <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
- <skip />
- <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
- <skip />
+ <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> – punjenje je na čekanju da bi se zaštitila baterija"</string>
+ <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> – provera dodatne opreme za punjenje"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"Preostalo je oko <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
<string name="power_discharging_duration" msgid="1076561255466053220">"Preostalo je oko <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
<string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Preostalo je oko <xliff:g id="TIME_REMAINING">%1$s</xliff:g> na osnovu korišćenja"</string>
@@ -489,12 +486,10 @@
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Bežično punjenje"</string>
<string name="battery_info_status_charging_dock" msgid="8573274094093364791">"Punjenje"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Ne puni se"</string>
- <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
- <skip />
+ <string name="battery_info_status_not_charging" msgid="1103084691314264664">"Uređaj je povezan, ali se ne puni"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Napunjeno"</string>
<string name="battery_info_status_full_charged" msgid="3536054261505567948">"Napunjeno do kraja"</string>
- <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
- <skip />
+ <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"Punjenje je na čekanju"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Kontroliše administrator"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Kontrolišu ograničena podešavanja"</string>
<string name="disabled" msgid="8017887509554714950">"Onemogućeno"</string>
diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml
index 53ffe11..b7e90bc 100644
--- a/packages/SettingsLib/res/values-bg/strings.xml
+++ b/packages/SettingsLib/res/values-bg/strings.xml
@@ -154,8 +154,7 @@
<string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"Изображения"</string>
<string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"Слушалки"</string>
<string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"Периферен вход"</string>
- <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
- <skip />
+ <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"Слухови апарати"</string>
<string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"Bluetooth"</string>
<string name="accessibility_wifi_off" msgid="1195445715254137155">"Wi-Fi е изключен."</string>
<string name="accessibility_no_wifi" msgid="5297119459491085771">"Няма връзка с Wi-Fi."</string>
@@ -457,10 +456,8 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"Функцията за корекция на цветовете може да бъде полезна, когато искате:<br/> <ol> <li>&nbsp;да виждате по-точни цветове;</li> <li>&nbsp;да премахнете цветовете, за да се съсредоточите.</li> </ol>"</string>
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"Заменено от „<xliff:g id="TITLE">%1$s</xliff:g>“"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
- <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
- <skip />
- <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
- <skip />
+ <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> – Зареждането е поставено на пауза с цел запазване на батерията"</string>
+ <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> – Аксесоарът за зареждане се проверява"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"Още около <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
<string name="power_discharging_duration" msgid="1076561255466053220">"Още около <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
<string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Още около <xliff:g id="TIME_REMAINING">%1$s</xliff:g> въз основа на използването"</string>
@@ -489,12 +486,10 @@
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Зарежда се безжично"</string>
<string name="battery_info_status_charging_dock" msgid="8573274094093364791">"Зареждане"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Не се зарежда"</string>
- <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
- <skip />
+ <string name="battery_info_status_not_charging" msgid="1103084691314264664">"Свързано, но не се зарежда"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Заредена"</string>
<string name="battery_info_status_full_charged" msgid="3536054261505567948">"Напълно заредено"</string>
- <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
- <skip />
+ <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"Зареждането е поставено на пауза"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Контролира се от администратор"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Управлява се чрез ограничена настройка"</string>
<string name="disabled" msgid="8017887509554714950">"Деактивирано"</string>
diff --git a/packages/SettingsLib/res/values-bs/strings.xml b/packages/SettingsLib/res/values-bs/strings.xml
index 006849e..d2bcfb6 100644
--- a/packages/SettingsLib/res/values-bs/strings.xml
+++ b/packages/SettingsLib/res/values-bs/strings.xml
@@ -154,7 +154,7 @@
<string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"Snimanje"</string>
<string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"Slušalice"</string>
<string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"Ulazni periferni uređaj"</string>
- <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"Slušna pomagala"</string>
+ <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"Slušni aparati"</string>
<string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"Bluetooth"</string>
<string name="accessibility_wifi_off" msgid="1195445715254137155">"WiFi je isključen."</string>
<string name="accessibility_no_wifi" msgid="5297119459491085771">"WiFi nije povezan."</string>
@@ -456,8 +456,8 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"Ispravka boja može biti korisna kada želite:<br/> <ol> <li>&nbsp;jasnije vidjeti boje</li> <li>&nbsp;ukloniti boje radi lakšeg fokusiranja</li> </ol>"</string>
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"Zamjenjuje <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
- <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> – punjenje je pauzirano radi zaštite baterije"</string>
- <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> – provjera dodatka za punjenje"</string>
+ <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> – punjenje je na čekanju radi zaštite baterije"</string>
+ <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> – provjera opreme za punjenje"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"Preostalo je još oko <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
<string name="power_discharging_duration" msgid="1076561255466053220">"Preostalo je još oko <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
<string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Preostalo je još oko <xliff:g id="TIME_REMAINING">%1$s</xliff:g> na osnovu vaše potrošnje"</string>
@@ -486,10 +486,10 @@
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Bežično punjenje"</string>
<string name="battery_info_status_charging_dock" msgid="8573274094093364791">"Punjenje"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Ne puni se"</string>
- <string name="battery_info_status_not_charging" msgid="1103084691314264664">"Povezano, ali se ne puni"</string>
+ <string name="battery_info_status_not_charging" msgid="1103084691314264664">"Uređaj je povezan, ali se ne puni"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Napunjeno"</string>
<string name="battery_info_status_full_charged" msgid="3536054261505567948">"Potpuno napunjeno"</string>
- <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"Punjenje na čekanju"</string>
+ <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"Punjenje je na čekanju"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Pod kontrolom administratora"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Kontrolira ograničena postavka"</string>
<string name="disabled" msgid="8017887509554714950">"Onemogućeno"</string>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index 6e95b3b..a556cf1 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -154,8 +154,7 @@
<string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"Imatges"</string>
<string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"Auricular"</string>
<string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"Perifèric d\'entrada"</string>
- <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
- <skip />
+ <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"Audiòfons"</string>
<string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"Bluetooth"</string>
<string name="accessibility_wifi_off" msgid="1195445715254137155">"Wi-Fi desactivada."</string>
<string name="accessibility_no_wifi" msgid="5297119459491085771">"Wi-Fi desconnectada."</string>
@@ -457,10 +456,8 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"La correcció de color pot ser útil si vols:<br/> <ol> <li>&nbsp;Veure els colors amb més precisió.</li> <li>&nbsp;Suprimir els colors per concentrar-te millor.</li> </ol>"</string>
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"S\'ha substituït per <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g>: <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
- <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
- <skip />
- <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
- <skip />
+ <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g>: la càrrega s\'ha posat en espera per protegir la bateria"</string>
+ <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g>: s\'està comprovant l\'accessori de càrrega"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"Temps restant aproximat: <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
<string name="power_discharging_duration" msgid="1076561255466053220">"Temps restant aproximat: <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
<string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Temps restant aproximat segons l\'ús que en fas: <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -489,12 +486,10 @@
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Carregant sense fil"</string>
<string name="battery_info_status_charging_dock" msgid="8573274094093364791">"S\'està carregant"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"No s\'està carregant"</string>
- <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
- <skip />
+ <string name="battery_info_status_not_charging" msgid="1103084691314264664">"Connectat, però sense carregar"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Carregada"</string>
<string name="battery_info_status_full_charged" msgid="3536054261505567948">"Totalment carregada"</string>
- <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
- <skip />
+ <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"Càrrega en espera"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Controlat per l\'administrador"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Controlat per la configuració restringida"</string>
<string name="disabled" msgid="8017887509554714950">"Desactivat"</string>
diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml
index 96ee652..45e089e 100644
--- a/packages/SettingsLib/res/values-cs/strings.xml
+++ b/packages/SettingsLib/res/values-cs/strings.xml
@@ -154,8 +154,7 @@
<string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"Zobrazovací zařízení"</string>
<string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"Sluchátka"</string>
<string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"Periferní vstupní zařízení"</string>
- <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
- <skip />
+ <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"Naslouchátka"</string>
<string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"Bluetooth"</string>
<string name="accessibility_wifi_off" msgid="1195445715254137155">"Síť Wi-Fi je vypnuta."</string>
<string name="accessibility_no_wifi" msgid="5297119459491085771">"Síť Wi-Fi je odpojena."</string>
@@ -457,10 +456,8 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"Korekce barev se může hodit, když chcete:<br/> <ol> <li>&nbsp;Vidět barvy přesněji.</li> <li>&nbsp;Odstranit barvy kvůli zlepšení soustředění.</li> </ol>"</string>
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"Přepsáno nastavením <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
- <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
- <skip />
- <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
- <skip />
+ <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> – Nabíjení je pozastaveno za účelem ochrany baterie"</string>
+ <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> – Kontrola nabíjecího příslušenství"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"Zbývá asi <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
<string name="power_discharging_duration" msgid="1076561255466053220">"Zbývá asi <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
<string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Při vašem obvyklém využití zbývá asi <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -489,12 +486,10 @@
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Bezdrátové nabíjení"</string>
<string name="battery_info_status_charging_dock" msgid="8573274094093364791">"Nabíjení"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Nenabíjí se"</string>
- <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
- <skip />
+ <string name="battery_info_status_not_charging" msgid="1103084691314264664">"Připojeno, ale nenabíjí se"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Nabito"</string>
<string name="battery_info_status_full_charged" msgid="3536054261505567948">"Plně nabito"</string>
- <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
- <skip />
+ <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"Nabíjení pozastaveno"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Spravováno administrátorem"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Spravováno omezeným nastavením"</string>
<string name="disabled" msgid="8017887509554714950">"Deaktivováno"</string>
diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml
index 61d0315..89d34a6 100644
--- a/packages/SettingsLib/res/values-da/strings.xml
+++ b/packages/SettingsLib/res/values-da/strings.xml
@@ -154,8 +154,7 @@
<string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"Billede"</string>
<string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"Hovedtelefoner"</string>
<string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"Eksterne inputenheder"</string>
- <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
- <skip />
+ <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"Høreapparater"</string>
<string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"Bluetooth"</string>
<string name="accessibility_wifi_off" msgid="1195445715254137155">"Wi-Fi er slået fra."</string>
<string name="accessibility_no_wifi" msgid="5297119459491085771">"Wi-Fi er afbrudt."</string>
@@ -457,10 +456,8 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"Farvekorrigering kan være en nyttig funktion, når du vil:<br/> <ol> <li>&nbsp;Se farver mere nøjagtigt</li> <li>&nbsp;Fjerne farver, så du nemmere kan fokusere</li> </ol>"</string>
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"Tilsidesat af <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
- <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
- <skip />
- <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
- <skip />
+ <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> – Opladningen er sat på pause for at beskytte batteriet"</string>
+ <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> – Tjekker opladningstilbehøret"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"Ca. <xliff:g id="TIME_REMAINING">%1$s</xliff:g> tilbage"</string>
<string name="power_discharging_duration" msgid="1076561255466053220">"Ca. <xliff:g id="TIME_REMAINING">%1$s</xliff:g> tilbage (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
<string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Ca. <xliff:g id="TIME_REMAINING">%1$s</xliff:g> tilbage, alt efter hvordan du bruger enheden"</string>
@@ -489,12 +486,10 @@
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Trådløs opladning"</string>
<string name="battery_info_status_charging_dock" msgid="8573274094093364791">"Oplader"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Oplader ikke"</string>
- <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
- <skip />
+ <string name="battery_info_status_not_charging" msgid="1103084691314264664">"Forbundet, men oplader ikke"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Opladet"</string>
<string name="battery_info_status_full_charged" msgid="3536054261505567948">"Fuldt opladet"</string>
- <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
- <skip />
+ <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"Opladningen er blevet sat på pause"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Kontrolleret af administratoren"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Styres af en begrænset indstilling"</string>
<string name="disabled" msgid="8017887509554714950">"Deaktiveret"</string>
diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml
index 2e4e507..b7df368 100644
--- a/packages/SettingsLib/res/values-el/strings.xml
+++ b/packages/SettingsLib/res/values-el/strings.xml
@@ -154,8 +154,7 @@
<string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"Απεικόνιση"</string>
<string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"Ακουστικά"</string>
<string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"Περιφερειακό εισόδου"</string>
- <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
- <skip />
+ <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"Βοηθήματα ακοής"</string>
<string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"Bluetooth"</string>
<string name="accessibility_wifi_off" msgid="1195445715254137155">"Wi-Fi ανενεργό."</string>
<string name="accessibility_no_wifi" msgid="5297119459491085771">"Το Wi-Fi έχει αποσυνδεθεί."</string>
@@ -457,10 +456,8 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"Η διόρθωση χρωμάτων μπορεί να σας φανεί χρήσιμη όταν θέλετε:<br/> <ol> <li>&nbsp;Μεγαλύτερη ακρίβεια στην απεικόνιση χρωμάτων</li> <li>&nbsp;Να καταργήσετε χρώματα για να συγκεντρωθείτε</li> </ol>"</string>
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"Αντικαταστάθηκε από <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
- <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
- <skip />
- <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
- <skip />
+ <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> – Η φόρτιση τέθηκε σε αναμονή για προστασία της μπαταρίας"</string>
+ <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> – Έλεγχος αξεσουάρ φόρτισης"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"Απομένει/ουν περίπου <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
<string name="power_discharging_duration" msgid="1076561255466053220">"Απομένει/ουν περίπου <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
<string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Απομένει/ουν περίπου <xliff:g id="TIME_REMAINING">%1$s</xliff:g>, βάσει της χρήσης σας"</string>
@@ -489,12 +486,10 @@
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Ασύρματη φόρτιση"</string>
<string name="battery_info_status_charging_dock" msgid="8573274094093364791">"Φόρτιση"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Δεν φορτίζει"</string>
- <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
- <skip />
+ <string name="battery_info_status_not_charging" msgid="1103084691314264664">"Συνδέθηκε, αλλά δεν φορτίζει"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Φορτισμένη"</string>
<string name="battery_info_status_full_charged" msgid="3536054261505567948">"Πλήρως φορτισμένο"</string>
- <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
- <skip />
+ <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"Η φόρτιση τέθηκε σε αναμονή"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Ελέγχονται από το διαχειριστή"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Ελέγχεται από τη Ρύθμιση με περιορισμό"</string>
<string name="disabled" msgid="8017887509554714950">"Απενεργοποιημένο"</string>
diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml
index 3c6e70e..66aaaf5 100644
--- a/packages/SettingsLib/res/values-en-rAU/strings.xml
+++ b/packages/SettingsLib/res/values-en-rAU/strings.xml
@@ -154,8 +154,7 @@
<string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"Imaging"</string>
<string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"Headphone"</string>
<string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"Input Peripheral"</string>
- <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
- <skip />
+ <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"Hearing aids"</string>
<string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"Bluetooth"</string>
<string name="accessibility_wifi_off" msgid="1195445715254137155">"Wi-Fi off."</string>
<string name="accessibility_no_wifi" msgid="5297119459491085771">"Wi-Fi disconnected."</string>
@@ -457,10 +456,8 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"Colour correction can be helpful when you want to:<br/> <ol> <li>&nbsp;See colours more accurately</li> <li>&nbsp;Remove colours to help you focus</li> </ol>"</string>
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"Overridden by <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
- <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
- <skip />
- <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
- <skip />
+ <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> – Charging on hold to protect battery"</string>
+ <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> – Checking charging accessory"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"About <xliff:g id="TIME_REMAINING">%1$s</xliff:g> left"</string>
<string name="power_discharging_duration" msgid="1076561255466053220">"About <xliff:g id="TIME_REMAINING">%1$s</xliff:g> left (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
<string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"About <xliff:g id="TIME_REMAINING">%1$s</xliff:g> left based on your usage"</string>
@@ -489,12 +486,10 @@
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Charging wirelessly"</string>
<string name="battery_info_status_charging_dock" msgid="8573274094093364791">"Charging"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Not charging"</string>
- <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
- <skip />
+ <string name="battery_info_status_not_charging" msgid="1103084691314264664">"Connected, but not charging"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Charged"</string>
<string name="battery_info_status_full_charged" msgid="3536054261505567948">"Fully charged"</string>
- <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
- <skip />
+ <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"Charging on hold"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Controlled by admin"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Controlled by restricted setting"</string>
<string name="disabled" msgid="8017887509554714950">"Disabled"</string>
diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml
index 3c6e70e..66aaaf5 100644
--- a/packages/SettingsLib/res/values-en-rGB/strings.xml
+++ b/packages/SettingsLib/res/values-en-rGB/strings.xml
@@ -154,8 +154,7 @@
<string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"Imaging"</string>
<string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"Headphone"</string>
<string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"Input Peripheral"</string>
- <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
- <skip />
+ <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"Hearing aids"</string>
<string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"Bluetooth"</string>
<string name="accessibility_wifi_off" msgid="1195445715254137155">"Wi-Fi off."</string>
<string name="accessibility_no_wifi" msgid="5297119459491085771">"Wi-Fi disconnected."</string>
@@ -457,10 +456,8 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"Colour correction can be helpful when you want to:<br/> <ol> <li>&nbsp;See colours more accurately</li> <li>&nbsp;Remove colours to help you focus</li> </ol>"</string>
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"Overridden by <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
- <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
- <skip />
- <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
- <skip />
+ <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> – Charging on hold to protect battery"</string>
+ <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> – Checking charging accessory"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"About <xliff:g id="TIME_REMAINING">%1$s</xliff:g> left"</string>
<string name="power_discharging_duration" msgid="1076561255466053220">"About <xliff:g id="TIME_REMAINING">%1$s</xliff:g> left (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
<string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"About <xliff:g id="TIME_REMAINING">%1$s</xliff:g> left based on your usage"</string>
@@ -489,12 +486,10 @@
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Charging wirelessly"</string>
<string name="battery_info_status_charging_dock" msgid="8573274094093364791">"Charging"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Not charging"</string>
- <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
- <skip />
+ <string name="battery_info_status_not_charging" msgid="1103084691314264664">"Connected, but not charging"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Charged"</string>
<string name="battery_info_status_full_charged" msgid="3536054261505567948">"Fully charged"</string>
- <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
- <skip />
+ <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"Charging on hold"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Controlled by admin"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Controlled by restricted setting"</string>
<string name="disabled" msgid="8017887509554714950">"Disabled"</string>
diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml
index 3c6e70e..66aaaf5 100644
--- a/packages/SettingsLib/res/values-en-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-en-rIN/strings.xml
@@ -154,8 +154,7 @@
<string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"Imaging"</string>
<string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"Headphone"</string>
<string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"Input Peripheral"</string>
- <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
- <skip />
+ <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"Hearing aids"</string>
<string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"Bluetooth"</string>
<string name="accessibility_wifi_off" msgid="1195445715254137155">"Wi-Fi off."</string>
<string name="accessibility_no_wifi" msgid="5297119459491085771">"Wi-Fi disconnected."</string>
@@ -457,10 +456,8 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"Colour correction can be helpful when you want to:<br/> <ol> <li>&nbsp;See colours more accurately</li> <li>&nbsp;Remove colours to help you focus</li> </ol>"</string>
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"Overridden by <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
- <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
- <skip />
- <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
- <skip />
+ <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> – Charging on hold to protect battery"</string>
+ <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> – Checking charging accessory"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"About <xliff:g id="TIME_REMAINING">%1$s</xliff:g> left"</string>
<string name="power_discharging_duration" msgid="1076561255466053220">"About <xliff:g id="TIME_REMAINING">%1$s</xliff:g> left (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
<string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"About <xliff:g id="TIME_REMAINING">%1$s</xliff:g> left based on your usage"</string>
@@ -489,12 +486,10 @@
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Charging wirelessly"</string>
<string name="battery_info_status_charging_dock" msgid="8573274094093364791">"Charging"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Not charging"</string>
- <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
- <skip />
+ <string name="battery_info_status_not_charging" msgid="1103084691314264664">"Connected, but not charging"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Charged"</string>
<string name="battery_info_status_full_charged" msgid="3536054261505567948">"Fully charged"</string>
- <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
- <skip />
+ <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"Charging on hold"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Controlled by admin"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Controlled by restricted setting"</string>
<string name="disabled" msgid="8017887509554714950">"Disabled"</string>
diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
index 19f8b21..5e496cd 100644
--- a/packages/SettingsLib/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
@@ -181,7 +181,7 @@
<string name="launch_defaults_none" msgid="8049374306261262709">"Sin configuraciones predeterminadas"</string>
<string name="tts_settings" msgid="8130616705989351312">"Configuración de texto a voz"</string>
<string name="tts_settings_title" msgid="7602210956640483039">"Salida de texto a voz"</string>
- <string name="tts_default_rate_title" msgid="3964187817364304022">"Velocidad de voz"</string>
+ <string name="tts_default_rate_title" msgid="3964187817364304022">"Velocidad de habla"</string>
<string name="tts_default_rate_summary" msgid="3781937042151716987">"Velocidad en la que se habla el texto"</string>
<string name="tts_default_pitch_title" msgid="6988592215554485479">"Tono"</string>
<string name="tts_default_pitch_summary" msgid="9132719475281551884">"Afecta el tono de la voz sintetizada"</string>
diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
index 8334379a..3ce371f 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -154,8 +154,7 @@
<string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"Escáner"</string>
<string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"Auriculares"</string>
<string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"Periférico de entrada"</string>
- <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
- <skip />
+ <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"Audífonos"</string>
<string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"Bluetooth"</string>
<string name="accessibility_wifi_off" msgid="1195445715254137155">"Wi-Fi desactivado."</string>
<string name="accessibility_no_wifi" msgid="5297119459491085771">"Wi-Fi desconectado."</string>
@@ -457,10 +456,8 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"Corrección de color puede ser útil si quieres:<br/> <ol> <li>&nbsp;Ver los colores mejor</li> <li>&nbsp;Quitar los colores para concentrarte mejor</li> </ol>"</string>
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"Anulado por <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g>: <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
- <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
- <skip />
- <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
- <skip />
+ <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - Carga pausada para proteger la batería"</string>
+ <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - Comprobando accesorio de carga"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"Tiempo restante aproximado: <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
<string name="power_discharging_duration" msgid="1076561255466053220">"Tiempo restante aproximado: <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
<string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Tiempo restante aproximado según tu uso: <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -489,12 +486,10 @@
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Carga inalámbrica"</string>
<string name="battery_info_status_charging_dock" msgid="8573274094093364791">"Cargando"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"No se está cargando"</string>
- <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
- <skip />
+ <string name="battery_info_status_not_charging" msgid="1103084691314264664">"Conectado, pero sin cargar"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Cargada"</string>
<string name="battery_info_status_full_charged" msgid="3536054261505567948">"Carga completa"</string>
- <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
- <skip />
+ <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"Carga pausada"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Controlada por el administrador"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Controlado por ajustes restringidos"</string>
<string name="disabled" msgid="8017887509554714950">"Inhabilitada"</string>
diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml
index 35fd2da..115a64a 100644
--- a/packages/SettingsLib/res/values-et/strings.xml
+++ b/packages/SettingsLib/res/values-et/strings.xml
@@ -154,8 +154,7 @@
<string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"Pildindus"</string>
<string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"Kõrvaklapid"</string>
<string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"Sisestatud välisseade"</string>
- <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
- <skip />
+ <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"Kuuldeaparaadid"</string>
<string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"Bluetooth"</string>
<string name="accessibility_wifi_off" msgid="1195445715254137155">"WiFi on välja lülitatud."</string>
<string name="accessibility_no_wifi" msgid="5297119459491085771">"WiFi-ühendus on katkestatud."</string>
@@ -457,10 +456,8 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"Värvide korrigeerimisest võib abi olla, kui soovite:<br/> <ol> <li>&nbsp;värve täpsemalt näha;</li> <li>&nbsp;värve eemaldada, et paremini keskenduda.</li> </ol>"</string>
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"Alistas <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
- <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
- <skip />
- <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
- <skip />
+ <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> – laadimine on aku kaitsmiseks ootele pandud"</string>
+ <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> – laadimistarviku kontrollimine"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"Ligikaudu <xliff:g id="TIME_REMAINING">%1$s</xliff:g> jäänud"</string>
<string name="power_discharging_duration" msgid="1076561255466053220">"Ligikaudu <xliff:g id="TIME_REMAINING">%1$s</xliff:g> jäänud (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
<string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Teie kasutuse põhjal on jäänud ligikaudu <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -489,12 +486,10 @@
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Juhtmevaba laadimine"</string>
<string name="battery_info_status_charging_dock" msgid="8573274094093364791">"Laadimine"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Ei lae"</string>
- <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
- <skip />
+ <string name="battery_info_status_not_charging" msgid="1103084691314264664">"Ühendatud, kuid ei laadita"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Laetud"</string>
<string name="battery_info_status_full_charged" msgid="3536054261505567948">"Täielikult laetud"</string>
- <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
- <skip />
+ <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"Laadimine on ootele pandud"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Juhib administraator"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Haldavad piiranguga seaded"</string>
<string name="disabled" msgid="8017887509554714950">"Keelatud"</string>
diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml
index 89ab3a4..f1e507e 100644
--- a/packages/SettingsLib/res/values-eu/strings.xml
+++ b/packages/SettingsLib/res/values-eu/strings.xml
@@ -154,8 +154,7 @@
<string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"Irudietarako gailua"</string>
<string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"Entzungailua"</string>
<string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"Idazteko gailua"</string>
- <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
- <skip />
+ <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"Audifonoak"</string>
<string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"Bluetooth bidezko gailua"</string>
<string name="accessibility_wifi_off" msgid="1195445715254137155">"Desaktibatuta dago wifi-konexioa."</string>
<string name="accessibility_no_wifi" msgid="5297119459491085771">"Deskonektatu egin da wifi-konexioa."</string>
@@ -457,10 +456,8 @@
<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>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
- <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
- <skip />
- <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
- <skip />
+ <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g>: kargatze-prozesua zain dago bateria babesteko"</string>
+ <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g>: kargatzeko osagarria egiaztatzen"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g> inguru gelditzen dira"</string>
<string name="power_discharging_duration" msgid="1076561255466053220">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g> inguru gelditzen dira (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
<string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Erabilera kontuan izanda, <xliff:g id="TIME_REMAINING">%1$s</xliff:g> inguru gelditzen dira"</string>
@@ -489,12 +486,10 @@
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Hari gabe kargatzen"</string>
<string name="battery_info_status_charging_dock" msgid="8573274094093364791">"Kargatzen"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Ez da kargatzen ari"</string>
- <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
- <skip />
+ <string name="battery_info_status_not_charging" msgid="1103084691314264664">"Konektatuta dago, baina ez da kargatzen ari"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Kargatuta"</string>
<string name="battery_info_status_full_charged" msgid="3536054261505567948">"Erabat kargatuta"</string>
- <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
- <skip />
+ <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"Kargatze-prozesua zain dago"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Administratzaileak kontrolatzen du"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Ezarpen mugatuak kontrolatzen du"</string>
<string name="disabled" msgid="8017887509554714950">"Desgaituta"</string>
diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
index cb6d27b..5d23510 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -154,8 +154,7 @@
<string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"Imagerie"</string>
<string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"Écouteurs"</string>
<string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"Périphérique d\'entrée"</string>
- <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
- <skip />
+ <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"Prothèses auditives"</string>
<string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"Bluetooth"</string>
<string name="accessibility_wifi_off" msgid="1195445715254137155">"Wi-Fi désactivé."</string>
<string name="accessibility_no_wifi" msgid="5297119459491085771">"Wi-Fi déconnecté."</string>
@@ -457,10 +456,8 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"La correction des couleurs peut être utile lorsque vous souhaitez :<br/> <ol> <li> voir les couleurs avec plus de précision;</li> <li> retirer les couleurs pour vous aider à vous concentrer.</li> </ol>"</string>
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"Remplacé par <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> : <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
- <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
- <skip />
- <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
- <skip />
+ <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> – La recharge a été mise en pause pour protéger la pile"</string>
+ <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> – Vérification de l\'accessoire de recharge en cours…"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"Il reste environ <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
<string name="power_discharging_duration" msgid="1076561255466053220">"Il reste environ <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
<string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Il reste environ <xliff:g id="TIME_REMAINING">%1$s</xliff:g> en fonction de votre usage"</string>
@@ -489,12 +486,10 @@
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"En recharge sans fil"</string>
<string name="battery_info_status_charging_dock" msgid="8573274094093364791">"Recharge en cours…"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"N\'est pas en charge"</string>
- <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
- <skip />
+ <string name="battery_info_status_not_charging" msgid="1103084691314264664">"Connecté, mais ne se recharge pas"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Chargée"</string>
<string name="battery_info_status_full_charged" msgid="3536054261505567948">"Complètement rechargée"</string>
- <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
- <skip />
+ <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"Recharge en pause"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Contrôlé par l\'administrateur"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Contrôlé par les paramètres restreints"</string>
<string name="disabled" msgid="8017887509554714950">"Désactivée"</string>
diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml
index 11d0838..75eb21f 100644
--- a/packages/SettingsLib/res/values-gl/strings.xml
+++ b/packages/SettingsLib/res/values-gl/strings.xml
@@ -154,8 +154,7 @@
<string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"Dispositivo de imaxe"</string>
<string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"Auriculares"</string>
<string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"Periférico de entrada"</string>
- <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
- <skip />
+ <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"Audiófonos"</string>
<string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"Bluetooth"</string>
<string name="accessibility_wifi_off" msgid="1195445715254137155">"Wifi desactivada."</string>
<string name="accessibility_no_wifi" msgid="5297119459491085771">"Wifi desconectada."</string>
@@ -457,10 +456,8 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"A corrección da cor pode serche útil se queres:<br/> <ol> <li>&nbsp;Ver mellor as cores</li> <li>&nbsp;Quitar as cores para concentrarte mellor</li> </ol>"</string>
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"Anulado por <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
- <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
- <skip />
- <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
- <skip />
+ <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g>. A carga púxose en pausa para protexer a batería"</string>
+ <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g>. Comprobando accesorio de carga"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"Tempo restante aproximado: <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
<string name="power_discharging_duration" msgid="1076561255466053220">"Tempo restante aproximado (<xliff:g id="LEVEL">%2$s</xliff:g>): <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
<string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Tempo restante aproximado en función do uso: <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -489,12 +486,10 @@
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Cargando sen fíos"</string>
<string name="battery_info_status_charging_dock" msgid="8573274094093364791">"Cargando"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Non se está cargando"</string>
- <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
- <skip />
+ <string name="battery_info_status_not_charging" msgid="1103084691314264664">"Conectado, pero non cargando"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Cargada"</string>
<string name="battery_info_status_full_charged" msgid="3536054261505567948">"Carga completa"</string>
- <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
- <skip />
+ <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"Carga en pausa"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Opción controlada polo administrador"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Baixo o control de opcións restrinxidas"</string>
<string name="disabled" msgid="8017887509554714950">"Desactivada"</string>
diff --git a/packages/SettingsLib/res/values-gu/strings.xml b/packages/SettingsLib/res/values-gu/strings.xml
index ebd02c3..e477063 100644
--- a/packages/SettingsLib/res/values-gu/strings.xml
+++ b/packages/SettingsLib/res/values-gu/strings.xml
@@ -154,8 +154,7 @@
<string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"ઇમેજિંગ"</string>
<string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"હેડફોન"</string>
<string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"ઇનપુટ પેરિફેરલ"</string>
- <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
- <skip />
+ <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"સાંભળવામાં મદદ આપતા યંત્રો"</string>
<string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"બ્લૂટૂથ"</string>
<string name="accessibility_wifi_off" msgid="1195445715254137155">"Wifi બંધ."</string>
<string name="accessibility_no_wifi" msgid="5297119459491085771">"Wifi ડિસ્કનેક્ટ થયું."</string>
@@ -457,10 +456,8 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"રંગમાં સુધારણા કરવાની સુવિધાનો ઉપયોગ ત્યારે સહાયરૂપ બની શકે છે કે જ્યારે તમે આ કરવા માગતા હો:<br/> <ol> <li>&nbsp;વધુ સચોટપણે રંગ જોવા</li> <li>&nbsp;ફોકસ કરવામાં સહાય માટે અમુક રંગ કાઢી નાખવા</li> </ol>"</string>
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> દ્વારા ઓવરરાઇડ થયું"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
- <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
- <skip />
- <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
- <skip />
+ <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - બૅટરીને સુરક્ષિત રાખવા માટે, ચાર્જિંગ હોલ્ડ પર રાખવામાં આવ્યું છે"</string>
+ <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - ચાર્જિંગ ઍક્સેસરી ચેક કરી રહ્યાં છીએ"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"લગભગ <xliff:g id="TIME_REMAINING">%1$s</xliff:g> બાકી છે"</string>
<string name="power_discharging_duration" msgid="1076561255466053220">"લગભગ <xliff:g id="TIME_REMAINING">%1$s</xliff:g> બાકી છે (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
<string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"તમારા વપરાશના આધારે લગભગ <xliff:g id="TIME_REMAINING">%1$s</xliff:g> બાકી છે"</string>
@@ -489,12 +486,10 @@
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"વાયરલેસથી ચાર્જિંગ"</string>
<string name="battery_info_status_charging_dock" msgid="8573274094093364791">"ચાર્જ થઈ રહ્યું છે"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"ચાર્જ થઈ રહ્યું નથી"</string>
- <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
- <skip />
+ <string name="battery_info_status_not_charging" msgid="1103084691314264664">"કનેક્ટેડ છે, પરંતુ ચાર્જ થઈ રહ્યું નથી"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"ચાર્જ થયું"</string>
<string name="battery_info_status_full_charged" msgid="3536054261505567948">"સંપૂર્ણપણે ચાર્જ છે"</string>
- <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
- <skip />
+ <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"ચાર્જિંગ હોલ્ડ પર રાખવામાં આવ્યું"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"વ્યવસ્થાપક દ્વારા નિયંત્રિત"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"પ્રતિબંધિત સેટિંગ દ્વારા નિયંત્રિત"</string>
<string name="disabled" msgid="8017887509554714950">"અક્ષમ કર્યો"</string>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index e03de15..0e91a37 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -154,8 +154,7 @@
<string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"इमेजिंग"</string>
<string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"हेडफ़ोन"</string>
<string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"इनपुट पेरिफ़ेरल"</string>
- <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
- <skip />
+ <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"कान की मशीनें"</string>
<string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"ब्लूटूथ"</string>
<string name="accessibility_wifi_off" msgid="1195445715254137155">"वाई-फ़ाई बंद है."</string>
<string name="accessibility_no_wifi" msgid="5297119459491085771">"वाई-फ़ाई डिसकनेक्ट है."</string>
@@ -457,10 +456,8 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"रंग में सुधार करने की सुविधा का इस्तेमाल, इन मामलों में किया जा सकता है:<br/> <ol> <li>&nbsp;आपको ज़्यादा सटीक तरह से रंग देखने हों</li> <li>&nbsp;ज़्यादा फ़ोकस करने के लिए, आपको कुछ खास रंग हटाने हों</li> </ol>"</string>
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> के द्वारा ओवरराइड किया गया"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
- <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
- <skip />
- <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
- <skip />
+ <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - बैटरी को सुरक्षित रखने के लिए, फ़ोन को चार्ज होने से रोक दिया गया है"</string>
+ <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - चार्जिंग ऐक्सेसरी की जांच की जा रही है"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"बैटरी करीब <xliff:g id="TIME_REMAINING">%1$s</xliff:g> में खत्म हो जाएगी"</string>
<string name="power_discharging_duration" msgid="1076561255466053220">"बैटरी करीब <xliff:g id="TIME_REMAINING">%1$s</xliff:g> में खत्म हो जाएगी (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
<string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"आपके इस्तेमाल के हिसाब से बैटरी करीब <xliff:g id="TIME_REMAINING">%1$s</xliff:g> में खत्म हो जाएगी"</string>
@@ -489,12 +486,10 @@
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"वायरलेस चार्जिंग"</string>
<string name="battery_info_status_charging_dock" msgid="8573274094093364791">"चार्ज हो रहा है"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"चार्ज नहीं हो रही है"</string>
- <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
- <skip />
+ <string name="battery_info_status_not_charging" msgid="1103084691314264664">"फ़ोन कनेक्ट हो गया, लेकिन चार्ज नहीं हो रहा है"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"बैटरी चार्ज हो गई"</string>
<string name="battery_info_status_full_charged" msgid="3536054261505567948">"बैटरी पूरी चार्ज है"</string>
- <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
- <skip />
+ <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"फ़ोन को चार्ज होने से रोक दिया गया है"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"इसका नियंत्रण एडमिन के पास है"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"इसे पाबंदी मोड वाली सेटिंग से कंट्रोल किया जाता है"</string>
<string name="disabled" msgid="8017887509554714950">"बंद किया गया"</string>
diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml
index 8bc6f66..1b28a0d 100644
--- a/packages/SettingsLib/res/values-hy/strings.xml
+++ b/packages/SettingsLib/res/values-hy/strings.xml
@@ -154,8 +154,7 @@
<string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"Պատկերներ"</string>
<string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"Ականջակալ"</string>
<string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"Մուտքի արտաքին սարքեր"</string>
- <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
- <skip />
+ <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"Լսողական սարք"</string>
<string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"Bluetooth"</string>
<string name="accessibility_wifi_off" msgid="1195445715254137155">"Wi-Fi-ն անջատված է:"</string>
<string name="accessibility_no_wifi" msgid="5297119459491085771">"Wi-Fi-ը կապակցված չէ:"</string>
@@ -457,10 +456,8 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"Գունաշտկումը կարող է օգնել, երբ դուք ուզում եք՝<br/> <ol> <li>&nbsp;Ավելի հստակ տեսնել գույները</li> <li>&nbsp;Հեռացնել գույները, որպեսզի կարողանաք կենտրոնանալ</li> </ol>"</string>
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"Գերազանցված է <xliff:g id="TITLE">%1$s</xliff:g>-ից"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
- <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
- <skip />
- <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
- <skip />
+ <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> – Լիցքավորումը դադարեցվել է՝ մարտկոցը պաշտպանելու համար"</string>
+ <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> – Լիցքավորման սարքը ստուգվում է"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"Լիցքը կբավարարի մոտ <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
<string name="power_discharging_duration" msgid="1076561255466053220">"Լիցքը (<xliff:g id="LEVEL">%2$s</xliff:g>) կբավարարի մոտ <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
<string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Լիցքը կբավարարի մոտ <xliff:g id="TIME_REMAINING">%1$s</xliff:g>՝ կախված օգտագործման եղանակից"</string>
@@ -489,12 +486,10 @@
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Անլար լիցքավորում"</string>
<string name="battery_info_status_charging_dock" msgid="8573274094093364791">"Լիցքավորում"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Չի լիցքավորվում"</string>
- <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
- <skip />
+ <string name="battery_info_status_not_charging" msgid="1103084691314264664">"Սարքը միացած է, սակայն չի լիցքավորվում"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Լիցքավորված է"</string>
<string name="battery_info_status_full_charged" msgid="3536054261505567948">"Լրիվ լիցքավորված է"</string>
- <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
- <skip />
+ <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"Լրցքավորումը դադարեցված է"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Վերահսկվում է ադմինիստրատորի կողմից"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Կառավարվում է սահմանափակ ռեժիմի կարգավորումներով"</string>
<string name="disabled" msgid="8017887509554714950">"Կասեցված է"</string>
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index 2f27c62..9e9c79c 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -154,8 +154,7 @@
<string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"Pencitraan"</string>
<string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"Headphone"</string>
<string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"Periferal Masukan"</string>
- <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
- <skip />
+ <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"Alat Bantu Dengar"</string>
<string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"Bluetooth"</string>
<string name="accessibility_wifi_off" msgid="1195445715254137155">"Wi-Fi tidak aktif."</string>
<string name="accessibility_no_wifi" msgid="5297119459491085771">"Wi-Fi tidak terhubung."</string>
@@ -457,10 +456,8 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"Koreksi warna dapat berguna jika Anda ingin:<br/> <ol> <li> Melihat warna dengan lebih akurat</li> <li> Menghapus warna agar Anda lebih fokus</li> </ol>"</string>
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"Digantikan oleh <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
- <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
- <skip />
- <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
- <skip />
+ <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - Pengisian daya dihentikan sementara untuk melindungi baterai"</string>
+ <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - Memeriksa aksesori pengisi daya"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"Sekitar <xliff:g id="TIME_REMAINING">%1$s</xliff:g> lagi"</string>
<string name="power_discharging_duration" msgid="1076561255466053220">"Sekitar <xliff:g id="TIME_REMAINING">%1$s</xliff:g> lagi (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
<string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Sekitar <xliff:g id="TIME_REMAINING">%1$s</xliff:g> lagi berdasarkan penggunaan Anda"</string>
@@ -489,12 +486,10 @@
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Mengisi daya nirkabel"</string>
<string name="battery_info_status_charging_dock" msgid="8573274094093364791">"Pengisian daya"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Tidak mengisi daya"</string>
- <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
- <skip />
+ <string name="battery_info_status_not_charging" msgid="1103084691314264664">"Terhubung, tetapi tidak mengisi daya"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Terisi"</string>
<string name="battery_info_status_full_charged" msgid="3536054261505567948">"Baterai Terisi Penuh"</string>
- <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
- <skip />
+ <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"Pengisian daya dihentikan sementara"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Dikontrol oleh admin"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Dikontrol oleh Setelan Terbatas"</string>
<string name="disabled" msgid="8017887509554714950">"Dinonaktifkan"</string>
diff --git a/packages/SettingsLib/res/values-is/strings.xml b/packages/SettingsLib/res/values-is/strings.xml
index c2d6de3..071597a 100644
--- a/packages/SettingsLib/res/values-is/strings.xml
+++ b/packages/SettingsLib/res/values-is/strings.xml
@@ -154,8 +154,7 @@
<string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"Myndherming"</string>
<string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"Heyrnartól"</string>
<string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"Jaðartæki með inntak"</string>
- <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
- <skip />
+ <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"Heyrnartæki"</string>
<string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"Bluetooth"</string>
<string name="accessibility_wifi_off" msgid="1195445715254137155">"Slökkt á Wi-Fi."</string>
<string name="accessibility_no_wifi" msgid="5297119459491085771">"Wi-Fi ótengt."</string>
@@ -457,10 +456,8 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"Litaleiðrétting kemur m.a. að gagni þegar þú vilt:<br/> <ol> <li>&nbsp;Sjá liti í aukinni skerpu</li> <li>&nbsp;Fjarlægja liti til að geta einbeitt þér betur</li> </ol>"</string>
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"Hnekkt af <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
- <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
- <skip />
- <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
- <skip />
+ <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> – Hleðsla í bið til að vernda rafhlöðuna"</string>
+ <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> – Athugar hleðslutæki"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"Um það bil <xliff:g id="TIME_REMAINING">%1$s</xliff:g> eftir"</string>
<string name="power_discharging_duration" msgid="1076561255466053220">"Um það bil <xliff:g id="TIME_REMAINING">%1$s</xliff:g> eftir (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
<string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Um það bil <xliff:g id="TIME_REMAINING">%1$s</xliff:g> eftir miðað við notkun þína"</string>
@@ -489,12 +486,10 @@
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Hleður þráðlaust"</string>
<string name="battery_info_status_charging_dock" msgid="8573274094093364791">"Í hleðslu"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Ekki í hleðslu"</string>
- <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
- <skip />
+ <string name="battery_info_status_not_charging" msgid="1103084691314264664">"Tækið er tengt en hleðst ekki"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Fullhlaðin"</string>
<string name="battery_info_status_full_charged" msgid="3536054261505567948">"Full hleðsla"</string>
- <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
- <skip />
+ <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"Hleðsla í bið"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Stjórnað af kerfisstjóra"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Stýrt af takmarkaði stillingu"</string>
<string name="disabled" msgid="8017887509554714950">"Óvirkt"</string>
diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
index 27b23b7..0540432 100644
--- a/packages/SettingsLib/res/values-it/strings.xml
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -154,8 +154,7 @@
<string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"Sistema di imaging"</string>
<string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"Cuffie"</string>
<string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"Periferica di immissione"</string>
- <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
- <skip />
+ <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"Apparecchi acustici"</string>
<string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"Bluetooth"</string>
<string name="accessibility_wifi_off" msgid="1195445715254137155">"Wi-Fi non attivo."</string>
<string name="accessibility_no_wifi" msgid="5297119459491085771">"Rete Wi-Fi scollegata."</string>
@@ -457,10 +456,8 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"La correzione del colore può essere utile quando vuoi:<br/> <ol> <li>&nbsp;Vedere i colori con più precisione</li> <li>&nbsp;Rimuovere i colori per mettere meglio a fuoco</li> </ol>"</string>
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"Valore sostituito da <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
- <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
- <skip />
- <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
- <skip />
+ <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - Ricarica in sospeso per proteggere la batteria"</string>
+ <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - Controllo dell\'accessorio di ricarica"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"Tempo rimanente: <xliff:g id="TIME_REMAINING">%1$s</xliff:g> circa"</string>
<string name="power_discharging_duration" msgid="1076561255466053220">"Tempo rimanente: <xliff:g id="TIME_REMAINING">%1$s</xliff:g> circa (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
<string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Tempo rimanente in base al tuo utilizzo: <xliff:g id="TIME_REMAINING">%1$s</xliff:g> circa"</string>
@@ -489,12 +486,10 @@
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"In carica, wireless"</string>
<string name="battery_info_status_charging_dock" msgid="8573274094093364791">"In carica"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Non in carica"</string>
- <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
- <skip />
+ <string name="battery_info_status_not_charging" msgid="1103084691314264664">"Connesso, ma non in carica"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Carica"</string>
<string name="battery_info_status_full_charged" msgid="3536054261505567948">"Batteria completamente carica"</string>
- <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
- <skip />
+ <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"Ricarica in sospeso"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Gestita dall\'amministratore"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Gestita tramite impostazioni con restrizioni"</string>
<string name="disabled" msgid="8017887509554714950">"Disattivato"</string>
diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
index 0c3c4f7..6dbf7ab 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -154,8 +154,7 @@
<string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"הדמיה"</string>
<string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"אוזניות"</string>
<string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"ציוד קלט היקפי"</string>
- <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
- <skip />
+ <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"מכשירי שמיעה"</string>
<string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"Bluetooth"</string>
<string name="accessibility_wifi_off" msgid="1195445715254137155">"Wi-Fi כבוי."</string>
<string name="accessibility_no_wifi" msgid="5297119459491085771">"Wi-Fi מנותק."</string>
@@ -457,10 +456,8 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"תיקון הצבע יכול לעזור אם רוצים:<br/> <ol> <li>&nbsp;לראות צבעים מדויקים יותר</li> <li>&nbsp;לראות פחות צבעים כדי לשפר את הריכוז</li> </ol>"</string>
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"נעקף על ידי <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
- <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
- <skip />
- <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
- <skip />
+ <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> – הטעינה הושהתה כדי להגן על הסוללה"</string>
+ <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> – מתבצעת בדיקה של אביזר הטעינה"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"הזמן הנותר: בערך <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
<string name="power_discharging_duration" msgid="1076561255466053220">"הזמן הנותר: בערך <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
<string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"הזמן הנותר על סמך השימוש שלך: בערך <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -489,12 +486,10 @@
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"בטעינה אלחוטית"</string>
<string name="battery_info_status_charging_dock" msgid="8573274094093364791">"טעינה"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"לא בטעינה"</string>
- <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
- <skip />
+ <string name="battery_info_status_not_charging" msgid="1103084691314264664">"המכשיר מחובר אבל לא נטען"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"הסוללה טעונה"</string>
<string name="battery_info_status_full_charged" msgid="3536054261505567948">"טעונה במלואה"</string>
- <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
- <skip />
+ <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"הטעינה הושהתה"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"נמצא בשליטת מנהל מערכת"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"בשליטה של הגדרה מוגבלת"</string>
<string name="disabled" msgid="8017887509554714950">"מושבת"</string>
@@ -527,7 +522,7 @@
<string name="ims_reg_title" msgid="8197592958123671062">"סטטוס הרשמה ל-IMS"</string>
<string name="ims_reg_status_registered" msgid="884916398194885457">"רשום"</string>
<string name="ims_reg_status_not_registered" msgid="2989287366045704694">"לא רשום"</string>
- <string name="status_unavailable" msgid="5279036186589861608">"לא זמין"</string>
+ <string name="status_unavailable" msgid="5279036186589861608">"לא זמינה"</string>
<string name="wifi_status_mac_randomized" msgid="466382542497832189">"כתובת ה-MAC אקראית"</string>
<string name="wifi_tether_connected_summary" msgid="5100712926640492336">"{count,plural, =1{מכשיר אחד מחובר}one{# מכשירים מחוברים}two{# מכשירים מחוברים}other{# מכשירים מחוברים}}"</string>
<string name="accessibility_manual_zen_more_time" msgid="5141801092071134235">"יותר זמן."</string>
diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml
index 3f71b39..cc560b8 100644
--- a/packages/SettingsLib/res/values-kk/strings.xml
+++ b/packages/SettingsLib/res/values-kk/strings.xml
@@ -154,8 +154,7 @@
<string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"Бейне құралы"</string>
<string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"Құлақаспап"</string>
<string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"Кіріс құралы"</string>
- <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
- <skip />
+ <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"Есту аппараттары"</string>
<string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"Bluetooth"</string>
<string name="accessibility_wifi_off" msgid="1195445715254137155">"Wi-Fi өшірулі."</string>
<string name="accessibility_no_wifi" msgid="5297119459491085771">"Wi-Fi ажыратылған."</string>
@@ -457,10 +456,8 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"Түсті түзету мына жағдайларда пайдалы болуы мүмкін:<br/> <ol> <li>&nbsp;түстерді анығырақ көру;</li> <li>&nbsp;зейін қоюға көмектесу үшін түстерді алып тастау.</li> </ol>"</string>
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> үстінен басқан"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
- <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
- <skip />
- <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
- <skip />
+ <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g>: батареяны қорғау үшін зарядтау кідіртіледі."</string>
+ <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g>: зарядтау құрылғысы тексеріледі."</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"Шамамен <xliff:g id="TIME_REMAINING">%1$s</xliff:g> қалды"</string>
<string name="power_discharging_duration" msgid="1076561255466053220">"Шамамен <xliff:g id="TIME_REMAINING">%1$s</xliff:g> қалды (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
<string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Пайдалану деректеріңізге сәйкес енді шамамен <xliff:g id="TIME_REMAINING">%1$s</xliff:g> қалды"</string>
@@ -489,12 +486,10 @@
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Сымсыз зарядталуда"</string>
<string name="battery_info_status_charging_dock" msgid="8573274094093364791">"Зарядталып жатыр."</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Зарядталу орындалып жатқан жоқ"</string>
- <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
- <skip />
+ <string name="battery_info_status_not_charging" msgid="1103084691314264664">"Құрылғы жалғанған, бірақ зарядталып жатқан жоқ."</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Зарядталды"</string>
<string name="battery_info_status_full_charged" msgid="3536054261505567948">"Толық зарядталды."</string>
- <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
- <skip />
+ <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"Зарядтау кідіртілді."</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Әкімші басқарады"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Шектелген параметрлер арқылы басқарылады."</string>
<string name="disabled" msgid="8017887509554714950">"Өшірілген"</string>
diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml
index e7f0220..0288e92 100644
--- a/packages/SettingsLib/res/values-kn/strings.xml
+++ b/packages/SettingsLib/res/values-kn/strings.xml
@@ -154,8 +154,7 @@
<string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"ಇಮೇಜಿಂಗ್"</string>
<string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"ಹೆಡ್ಫೋನ್"</string>
<string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"ಪೆರಿಪೆರಲ್ ಇನ್ಪುಟ್"</string>
- <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
- <skip />
+ <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"ಶ್ರವಣ ಸಾಧನಗಳು"</string>
<string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"ಬ್ಲೂಟೂತ್"</string>
<string name="accessibility_wifi_off" msgid="1195445715254137155">"ವೈಫೈ ಆಫ್."</string>
<string name="accessibility_no_wifi" msgid="5297119459491085771">"ವೈಫೈ ಸಂಪರ್ಕ ಕಡಿತಗೊಂಡಿದೆ."</string>
@@ -457,10 +456,8 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"ನೀವು ಹೆಚ್ಚು ಸ್ಪಷ್ಟವಾದ ಬಣ್ಣಗಳನ್ನು ನೋಡಲು ಬಯಸಿದರೆ :<br/> <ol> <li>&nbsp; ಬಣ್ಣದ ತಿದ್ದುಪಡಿಯು ಸಹಾಯಕವಾಗಿರುತ್ತದೆ; ಗಮನವನ್ನು ಕೇಂದ್ರೀಕರಿಸಲು ನಿಮಗೆ ಸಹಾಯ ಮಾಡಲು ಬಣ್ಣಗಳನ್ನು ತೆಗೆದುಹಾಕಿ </li> </ol>"</string>
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> ಮೂಲಕ ಅತಿಕ್ರಮಿಸುತ್ತದೆ"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
- <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
- <skip />
- <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
- <skip />
+ <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - ಬ್ಯಾಟರಿಯನ್ನು ರಕ್ಷಿಸಲು ಚಾರ್ಜಿಂಗ್ ಅನ್ನು ಹೋಲ್ಡ್ ಮಾಡಲಾಗಿದೆ"</string>
+ <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - ಚಾರ್ಜಿಂಗ್ ಪರಿಕರವನ್ನು ಪರಿಶೀಲಿಸಲಾಗುತ್ತಿದೆ"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g> ಸಮಯ ಬಾಕಿ ಉಳಿದಿದೆ"</string>
<string name="power_discharging_duration" msgid="1076561255466053220">"(<xliff:g id="LEVEL">%2$s</xliff:g>) ತಲುಪಲು <xliff:g id="TIME_REMAINING">%1$s</xliff:g> ಸಮಯ ಬಾಕಿ ಉಳಿದಿದೆ"</string>
<string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"ನಿಮ್ಮ ಬಳಕೆಯ ಆಧಾರದ ಮೇಲೆ ಸುಮಾರು <xliff:g id="TIME_REMAINING">%1$s</xliff:g> ಸಮಯ ಬಾಕಿ ಉಳಿದಿದೆ"</string>
@@ -489,12 +486,10 @@
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"ವೈರ್ಲೆಸ್ ಚಾರ್ಜಿಂಗ್"</string>
<string name="battery_info_status_charging_dock" msgid="8573274094093364791">"ಚಾರ್ಜ್ ಆಗುತ್ತಿದೆ"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"ಚಾರ್ಜ್ ಆಗುತ್ತಿಲ್ಲ"</string>
- <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
- <skip />
+ <string name="battery_info_status_not_charging" msgid="1103084691314264664">"ಕನೆಕ್ಟ್ ಮಾಡಲಾಗಿದೆ, ಆದರೆ ಚಾರ್ಜಿಂಗ್ ಆಗುತ್ತಿಲ್ಲ"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"ಚಾರ್ಜ್ ಆಗಿದೆ"</string>
<string name="battery_info_status_full_charged" msgid="3536054261505567948">"ಪೂರ್ಣವಾಗಿ ಚಾರ್ಜ್ ಆಗಿದೆ"</string>
- <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
- <skip />
+ <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"ಚಾರ್ಜಿಂಗ್ ಅನ್ನು ಹೋಲ್ಡ್ ಮಾಡಲಾಗಿದೆ"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"ನಿರ್ವಾಹಕರ ಮೂಲಕ ನಿಯಂತ್ರಿಸಲಾಗಿದೆ"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"ನಿರ್ಬಂಧಿಸಲಾದ ಸೆಟ್ಟಿಂಗ್ ಮೂಲಕ ನಿಯಂತ್ರಿಸಲಾಗುತ್ತದೆ"</string>
<string name="disabled" msgid="8017887509554714950">"ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ"</string>
diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
index df43494..432f4ed 100644
--- a/packages/SettingsLib/res/values-ko/strings.xml
+++ b/packages/SettingsLib/res/values-ko/strings.xml
@@ -154,8 +154,7 @@
<string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"이미징"</string>
<string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"헤드폰"</string>
<string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"입력 주변기기"</string>
- <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
- <skip />
+ <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"보청기"</string>
<string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"블루투스"</string>
<string name="accessibility_wifi_off" msgid="1195445715254137155">"Wi-Fi가 꺼져 있습니다."</string>
<string name="accessibility_no_wifi" msgid="5297119459491085771">"Wi-Fi 연결이 끊어졌습니다."</string>
@@ -457,10 +456,8 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"색상 보정은 다음과 같은 경우에 유용할 수 있습니다.<br/> <ol> <li>&nbsp;색상을 보다 정확하게 확인하려는 경우</li> <li>&nbsp;집중에 도움이 되도록 색상을 제거하려는 경우</li> </ol>"</string>
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> 우선 적용됨"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g>, <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
- <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
- <skip />
- <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
- <skip />
+ <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - 배터리 보호를 위해 충전 일시중지"</string>
+ <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - 충전 액세서리 확인 중"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"남은 시간: 약 <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
<string name="power_discharging_duration" msgid="1076561255466053220">"남은 시간 약 <xliff:g id="TIME_REMAINING">%1$s</xliff:g>(<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
<string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"내 사용량을 기준으로 약 <xliff:g id="TIME_REMAINING">%1$s</xliff:g> 남음"</string>
@@ -489,12 +486,10 @@
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"무선 충전 중"</string>
<string name="battery_info_status_charging_dock" msgid="8573274094093364791">"충전"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"충전 안함"</string>
- <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
- <skip />
+ <string name="battery_info_status_not_charging" msgid="1103084691314264664">"연결되었으나 충전 중이 아님"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"충전됨"</string>
<string name="battery_info_status_full_charged" msgid="3536054261505567948">"완전히 충전됨"</string>
- <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
- <skip />
+ <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"충전 일시중지"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"관리자가 제어"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"제한된 설정으로 제어됨"</string>
<string name="disabled" msgid="8017887509554714950">"사용 안함"</string>
diff --git a/packages/SettingsLib/res/values-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml
index 6e6926e..aa685a2 100644
--- a/packages/SettingsLib/res/values-ky/strings.xml
+++ b/packages/SettingsLib/res/values-ky/strings.xml
@@ -154,8 +154,7 @@
<string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"Сүрөт тартуучу түзмөк"</string>
<string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"Кулакчын"</string>
<string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"Дайындарды киргизүүчү тышкы түзмөк"</string>
- <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
- <skip />
+ <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"Угуу аппараттары"</string>
<string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"Bluetooth"</string>
<string name="accessibility_wifi_off" msgid="1195445715254137155">"Wifi өчүк."</string>
<string name="accessibility_no_wifi" msgid="5297119459491085771">"Wifi туташуусу жок."</string>
@@ -457,10 +456,8 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"Түстөрдү тууралоо менен:<br/> <ol> <li>&nbsp;Керектүү түстөрдү аласыз</li> <li>&nbsp;Алагды кылган түстөрдү өчүрүп саласыз</li> </ol>"</string>
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> менен алмаштырылган"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
- <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
- <skip />
- <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
- <skip />
+ <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - Батареяны коргоо үчүн кубаттоо тындырылды"</string>
+ <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - Кубаттоо шайманы текшерилүүдө"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"Болжол менен <xliff:g id="TIME_REMAINING">%1$s</xliff:g> калды"</string>
<string name="power_discharging_duration" msgid="1076561255466053220">"Болжол менен <xliff:g id="TIME_REMAINING">%1$s</xliff:g> калды (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
<string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Колдонгонуңузга караганда болжол менен <xliff:g id="TIME_REMAINING">%1$s</xliff:g> калды"</string>
@@ -489,12 +486,10 @@
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Зымсыз кубатталууда"</string>
<string name="battery_info_status_charging_dock" msgid="8573274094093364791">"Кубатталууда"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Кубат алган жок"</string>
- <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
- <skip />
+ <string name="battery_info_status_not_charging" msgid="1103084691314264664">"Туташкан, бирок кубатталбай жатат"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Кубатталды"</string>
<string name="battery_info_status_full_charged" msgid="3536054261505567948">"Толук кубатталды"</string>
- <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
- <skip />
+ <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"Кубаттоо күтүү режиминде"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Администратор тарабынан көзөмөлдөнөт"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Чектелген параметр аркылуу көзөмөлдөнөт"</string>
<string name="disabled" msgid="8017887509554714950">"Өчүрүлгөн"</string>
diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml
index 5e2f696..d0d9507 100644
--- a/packages/SettingsLib/res/values-lt/strings.xml
+++ b/packages/SettingsLib/res/values-lt/strings.xml
@@ -154,8 +154,7 @@
<string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"Vaizdavimo įrenginys"</string>
<string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"Ausinės"</string>
<string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"Išorinis įvesties įrenginys"</string>
- <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
- <skip />
+ <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"Klausos aparatai"</string>
<string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"Bluetooth"</string>
<string name="accessibility_wifi_off" msgid="1195445715254137155">"„Wi-Fi“ išjungtas."</string>
<string name="accessibility_no_wifi" msgid="5297119459491085771">"„Wi-Fi“ atjungtas."</string>
@@ -457,10 +456,8 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"Spalvų taisymas gali būti naudingas, kai norite:<br/> <ol> <li>&nbsp;aiškiau matyti spalvas;</li> <li>&nbsp;pašalinti spalvas, kad galėtumėte sutelkti dėmesį.</li> </ol>"</string>
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"Nepaisyta naudojant nuostatą „<xliff:g id="TITLE">%1$s</xliff:g>“"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
- <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
- <skip />
- <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
- <skip />
+ <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> – įkrovimas pristabdytas, siekiant apsaugoti akumuliatorių"</string>
+ <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> – tikrinamas įkrovimo priedas"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"Liko maždaug <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
<string name="power_discharging_duration" msgid="1076561255466053220">"Liko maždaug <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
<string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Liko maždaug <xliff:g id="TIME_REMAINING">%1$s</xliff:g>, atsižvelgiant į naudojimą"</string>
@@ -489,12 +486,10 @@
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Kraunama be laidų"</string>
<string name="battery_info_status_charging_dock" msgid="8573274094093364791">"Įkraunama"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Nekraunama"</string>
- <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
- <skip />
+ <string name="battery_info_status_not_charging" msgid="1103084691314264664">"Prijungta, bet nekraunama"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Įkrauta"</string>
<string name="battery_info_status_full_charged" msgid="3536054261505567948">"Visiškai įkrautas"</string>
- <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
- <skip />
+ <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"Įkrovimas pristabdytas"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Valdo administratorius"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Valdoma pagal apribotą nustatymą"</string>
<string name="disabled" msgid="8017887509554714950">"Neleidžiama"</string>
diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml
index f9bab6f..43a940b 100644
--- a/packages/SettingsLib/res/values-lv/strings.xml
+++ b/packages/SettingsLib/res/values-lv/strings.xml
@@ -154,8 +154,7 @@
<string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"Attēlu apstrādes ierīce"</string>
<string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"Austiņas"</string>
<string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"Ievades ierīce"</string>
- <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
- <skip />
+ <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"Dzirdes aparāti"</string>
<string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"Bluetooth"</string>
<string name="accessibility_wifi_off" msgid="1195445715254137155">"Wi-Fi savienojums izslēgts"</string>
<string name="accessibility_no_wifi" msgid="5297119459491085771">"Wi-Fi savienojums pārtraukts"</string>
@@ -457,10 +456,8 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"Krāsu korekcija var būt noderīga šādiem mērķiem:<br/> <ol> <li>&nbsp;precīzākai krāsu attēlošanai;</li> <li>&nbsp;krāsu noņemšanai, lai būtu vieglāk koncentrēties.</li> </ol>"</string>
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"Jaunā preference: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> — <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
- <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
- <skip />
- <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
- <skip />
+ <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> — uzlāde apturēta, lai aizsargātu akumulatoru"</string>
+ <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> — notiek uzlādes piederuma pārbaude"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"Aptuvenais atlikušais laiks: <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
<string name="power_discharging_duration" msgid="1076561255466053220">"Aptuvenais atlikušais laiks: <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
<string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Ņemot vērā lietojumu, atlikušais laiks: <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -489,12 +486,10 @@
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Bezvadu uzlāde"</string>
<string name="battery_info_status_charging_dock" msgid="8573274094093364791">"Notiek uzlāde"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Nenotiek uzlāde"</string>
- <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
- <skip />
+ <string name="battery_info_status_not_charging" msgid="1103084691314264664">"Savienota, taču netiek uzlādēta"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Uzlādēts"</string>
<string name="battery_info_status_full_charged" msgid="3536054261505567948">"Pilnībā uzlādēts"</string>
- <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
- <skip />
+ <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"Uzlāde apturēta"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Kontrolē administrators"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Kontrolē ierobežots iestatījums"</string>
<string name="disabled" msgid="8017887509554714950">"Atspējots"</string>
diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml
index aafa846..db5bdf4 100644
--- a/packages/SettingsLib/res/values-mk/strings.xml
+++ b/packages/SettingsLib/res/values-mk/strings.xml
@@ -154,8 +154,7 @@
<string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"Слики"</string>
<string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"Слушалка"</string>
<string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"Периферен влез"</string>
- <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
- <skip />
+ <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"Слушни помагала"</string>
<string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"Bluetooth"</string>
<string name="accessibility_wifi_off" msgid="1195445715254137155">"Wi-Fi е исклучено."</string>
<string name="accessibility_no_wifi" msgid="5297119459491085771">"Wi-Fi е исклучено."</string>
@@ -457,10 +456,8 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"Корекцијата на боите може да биде корисна кога сакате:<br/> <ol> <li>&nbsp;да ги гледате боите попрецизно</li> <li>&nbsp;да ги отстраните боите за полесно да се концентрирате</li> </ol>"</string>
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"Прескокнато според <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
- <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
- <skip />
- <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
- <skip />
+ <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - полнењето е паузирано за да се заштити батеријата"</string>
+ <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - се проверува додатокот за полнење"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"Уште околу <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
<string name="power_discharging_duration" msgid="1076561255466053220">"Уште околу <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
<string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Уште околу <xliff:g id="TIME_REMAINING">%1$s</xliff:g> според вашето користење"</string>
@@ -489,12 +486,10 @@
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Се полни безжично"</string>
<string name="battery_info_status_charging_dock" msgid="8573274094093364791">"Се полни"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Не се полни"</string>
- <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
- <skip />
+ <string name="battery_info_status_not_charging" msgid="1103084691314264664">"Поврзано, но не се полни"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Полна"</string>
<string name="battery_info_status_full_charged" msgid="3536054261505567948">"Целосно полна"</string>
- <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
- <skip />
+ <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"Полнењето е паузирано"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Контролирано од администраторот"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Контролирано со ограничени поставки"</string>
<string name="disabled" msgid="8017887509554714950">"Оневозможено"</string>
diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml
index c857a2b..787ce97 100644
--- a/packages/SettingsLib/res/values-mn/strings.xml
+++ b/packages/SettingsLib/res/values-mn/strings.xml
@@ -154,8 +154,7 @@
<string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"Зураглал"</string>
<string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"Чихэвч"</string>
<string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"Нэмэлт оролт"</string>
- <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
- <skip />
+ <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"Сонсголын төхөөрөмжүүд"</string>
<string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"Bluetooth"</string>
<string name="accessibility_wifi_off" msgid="1195445715254137155">"Wifi унтраалттай байна."</string>
<string name="accessibility_no_wifi" msgid="5297119459491085771">"Wifi холбогдоогүй байна."</string>
@@ -457,10 +456,8 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"Өнгө тохируулга нь таныг дараахыг хийхийг хүсэх үед хэрэгтэй байж болно:<br/> <ol> <li>&nbsp;Өнгөнүүдийг илүү нарийвчилж харах</li> <li>&nbsp;Төвлөрөхийн тулд өнгөнүүдийг хасах</li> </ol>"</string>
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"Давхарласан <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
- <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
- <skip />
- <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
- <skip />
+ <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - Батарейг хамгаалахын тулд цэнэглэхийг хүлээлгэсэн"</string>
+ <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - Цэнэглэх нэмэлт хэрэгслийг шалгаж байна"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"Ойролцоогоор <xliff:g id="TIME_REMAINING">%1$s</xliff:g> үлдсэн"</string>
<string name="power_discharging_duration" msgid="1076561255466053220">"Ойролцоогоор <xliff:g id="TIME_REMAINING">%1$s</xliff:g> үлдсэн (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
<string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Таны хэрэглээнд үндэслэн ойролцоогоор <xliff:g id="TIME_REMAINING">%1$s</xliff:g> үлдсэн"</string>
@@ -489,12 +486,10 @@
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Утасгүй цэнэглэж байна"</string>
<string name="battery_info_status_charging_dock" msgid="8573274094093364791">"Цэнэглэж байна"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Цэнэглэхгүй байна"</string>
- <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
- <skip />
+ <string name="battery_info_status_not_charging" msgid="1103084691314264664">"Холбогдсон ч цэнэглэхгүй байна"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Цэнэглэсэн"</string>
<string name="battery_info_status_full_charged" msgid="3536054261505567948">"Бүрэн цэнэглэсэн"</string>
- <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
- <skip />
+ <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"Цэнэглэхийг хүлээлгэд оруулсан"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Админ удирдсан"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Хязгаарлагдсан тохиргоогоор хянадаг"</string>
<string name="disabled" msgid="8017887509554714950">"Идэвхгүйжүүлсэн"</string>
diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml
index 26669b9..00482ea 100644
--- a/packages/SettingsLib/res/values-mr/strings.xml
+++ b/packages/SettingsLib/res/values-mr/strings.xml
@@ -154,8 +154,7 @@
<string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"इमेज"</string>
<string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"हेडफोन"</string>
<string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"इनपुट परिधीय"</string>
- <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
- <skip />
+ <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"श्रवणयंत्रे"</string>
<string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"ब्लूटूथ"</string>
<string name="accessibility_wifi_off" msgid="1195445715254137155">"वाय-फाय बंद."</string>
<string name="accessibility_no_wifi" msgid="5297119459491085771">"वाय-फाय डिस्कनेक्ट झाले."</string>
@@ -457,10 +456,8 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"तुम्हाला पुढील गोष्टी करायच्या असतील, तेव्हा रंग सुधारणेची मदत होऊ शकते:<br/> <ol> <li>&nbsp;रंग आणखी अचूकपणे पाहण्यासाठी</li> <li>&nbsp;तुम्हाला लक्ष केंद्रित करण्यात मदत करण्याकरिता रंग काढून टाकण्यासाठी</li> </ol>"</string>
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> द्वारे अधिलिखित"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
- <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
- <skip />
- <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
- <skip />
+ <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - बॅटरीचे संरक्षण करण्यासाठी चार्जिंग थांबवले आहे"</string>
+ <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - चार्जिंगसंबंधित ॲक्सेसरी तपासत आहे"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"अंदाजे <xliff:g id="TIME_REMAINING">%1$s</xliff:g> बाकी आहे"</string>
<string name="power_discharging_duration" msgid="1076561255466053220">"अंदाजे <xliff:g id="TIME_REMAINING">%1$s</xliff:g> बाकी आहे (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
<string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"तुमच्या वापरावर आधारित अंदाजे <xliff:g id="TIME_REMAINING">%1$s</xliff:g> बाकी आहे"</string>
@@ -489,12 +486,10 @@
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"वायरलेसने चार्ज होत आहे"</string>
<string name="battery_info_status_charging_dock" msgid="8573274094093364791">"चार्ज होत आहे"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"चार्ज होत नाही"</string>
- <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
- <skip />
+ <string name="battery_info_status_not_charging" msgid="1103084691314264664">"कनेक्ट केलेले आहे, पण चार्ज होत नाही"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"चार्ज झाली"</string>
<string name="battery_info_status_full_charged" msgid="3536054261505567948">"पूर्ण चार्ज झाली"</string>
- <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
- <skip />
+ <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"चार्जिंग थांबवले आहे"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"प्रशासकाने नियंत्रित केलेले"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"प्रतिबंधित केलेल्या सेटिंग द्वारे नियंत्रित"</string>
<string name="disabled" msgid="8017887509554714950">"अक्षम"</string>
diff --git a/packages/SettingsLib/res/values-ms/strings.xml b/packages/SettingsLib/res/values-ms/strings.xml
index dd31c85..bd3eb99 100644
--- a/packages/SettingsLib/res/values-ms/strings.xml
+++ b/packages/SettingsLib/res/values-ms/strings.xml
@@ -154,8 +154,7 @@
<string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"Pengimejan"</string>
<string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"Fon kepala"</string>
<string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"Persisian Input"</string>
- <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
- <skip />
+ <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"Alat Bantu Pendengaran"</string>
<string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"Bluetooth"</string>
<string name="accessibility_wifi_off" msgid="1195445715254137155">"Wi-Fi dimatikan."</string>
<string name="accessibility_no_wifi" msgid="5297119459491085771">"Wi-Fi diputuskan sambungannya."</string>
@@ -457,10 +456,8 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"Pembetulan warna dapat membantu apabila anda mahu:<br/> <ol> <li>&nbsp;Melihat warna dengan lebih tepat</li> <li>&nbsp;Mengalih keluar warna agar anda dapat menumpukan perhatian</li> </ol>"</string>
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"Diatasi oleh <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
- <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
- <skip />
- <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
- <skip />
+ <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - Pengecasan ditunda untuk melindungi bateri"</string>
+ <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - Memeriksa aksesori pengecasan"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"Kira-kira <xliff:g id="TIME_REMAINING">%1$s</xliff:g> lagi"</string>
<string name="power_discharging_duration" msgid="1076561255466053220">"Kira-kira <xliff:g id="TIME_REMAINING">%1$s</xliff:g> lagi (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
<string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Kira-kira <xliff:g id="TIME_REMAINING">%1$s</xliff:g> lagi berdasarkan penggunaan anda"</string>
@@ -489,12 +486,10 @@
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Mengecas tanpa wayar"</string>
<string name="battery_info_status_charging_dock" msgid="8573274094093364791">"Pengecasan"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Tidak mengecas"</string>
- <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
- <skip />
+ <string name="battery_info_status_not_charging" msgid="1103084691314264664">"Disambungkan tetapi tidak dicas"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Sudah dicas"</string>
<string name="battery_info_status_full_charged" msgid="3536054261505567948">"Dicas Penuh"</string>
- <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
- <skip />
+ <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"Pengecasan ditunda"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Dikawal oleh pentadbir"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Dikawal oleh Tetapan Terhad"</string>
<string name="disabled" msgid="8017887509554714950">"Dilumpuhkan"</string>
diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml
index 7c74e1b..c18b273 100644
--- a/packages/SettingsLib/res/values-my/strings.xml
+++ b/packages/SettingsLib/res/values-my/strings.xml
@@ -154,8 +154,7 @@
<string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"ဓာတ်ပုံဆိုင်ရာ"</string>
<string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"နားကြပ်"</string>
<string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"ချိတ်ဆက်အသုံးပြုရသည့် စက်ပစ္စည်းများ"</string>
- <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
- <skip />
+ <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"နားကြားကိရိယာ"</string>
<string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"ဘလူးတုသ်"</string>
<string name="accessibility_wifi_off" msgid="1195445715254137155">"Wi-Fi ပိတ်ထားသည်"</string>
<string name="accessibility_no_wifi" msgid="5297119459491085771">"Wi-Fi ချိတ်ဆက်ထားမှု မရှိပါ"</string>
@@ -457,10 +456,8 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"အရောင် အမှန်ပြင်ခြင်းသည် အောက်ပါတို့အတွက် အသုံးဝင်နိုင်သည်-<br/> <ol> <li>&nbsp;အရောင်များကို ပိုမိုမှန်ကန်စွာ ကြည့်ရှုခြင်း</li> <li>&nbsp;အာရုံစိုက်နိုင်ရန် အရောင်များ ဖယ်ရှားခြင်း</li> </ol>"</string>
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> မှ ကျော်၍ လုပ်ထားသည်။"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
- <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
- <skip />
- <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
- <skip />
+ <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - ဘက်ထရီကာကွယ်ရန် အားသွင်းခြင်းကို ခဏရပ်ထားသည်"</string>
+ <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - အားသွင်းပစ္စည်း စစ်ဆေးနေသည်"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g> ခန့် ကျန်သည်"</string>
<string name="power_discharging_duration" msgid="1076561255466053220">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g> ခန့် ကျန်သည် (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
<string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"သင်၏ အသုံးပြုမှု အပေါ် မူတည်၍ <xliff:g id="TIME_REMAINING">%1$s</xliff:g> ခန့် ကျန်သည်"</string>
@@ -489,12 +486,10 @@
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"ကြိုးမဲ့ အားသွင်းနေသည်"</string>
<string name="battery_info_status_charging_dock" msgid="8573274094093364791">"အားသွင်းနေသည်"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"အားသွင်းမနေပါ"</string>
- <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
- <skip />
+ <string name="battery_info_status_not_charging" msgid="1103084691314264664">"ချိတ်ဆက်ထားသော်လည်း အားသွင်းမနေပါ"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"အားသွင်းပြီးပါပြီ"</string>
<string name="battery_info_status_full_charged" msgid="3536054261505567948">"အားအပြည့်သွင်းထားသည်"</string>
- <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
- <skip />
+ <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"အားသွင်းခြင်းကို ခဏရပ်ထားသည်"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"စီမံခန့်ခွဲသူမှ ထိန်းချုပ်ပါသည်"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"ကန့်သတ်ထားသော ဆက်တင်များဖြင့် ထိန်းချုပ်ထားသည်"</string>
<string name="disabled" msgid="8017887509554714950">"ပိတ်ထားပြီး"</string>
diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml
index 4782f26..b3c4295 100644
--- a/packages/SettingsLib/res/values-nb/strings.xml
+++ b/packages/SettingsLib/res/values-nb/strings.xml
@@ -154,8 +154,7 @@
<string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"Bildefremviser"</string>
<string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"Øretelefoner"</string>
<string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"Inndata fra ytre utstyrsenheter"</string>
- <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
- <skip />
+ <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"Høreapparater"</string>
<string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"Bluetooth"</string>
<string name="accessibility_wifi_off" msgid="1195445715254137155">"Wifi er av."</string>
<string name="accessibility_no_wifi" msgid="5297119459491085771">"Wifi er frakoblet."</string>
@@ -457,10 +456,8 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"Fargekorrigering kan være nyttig når du vil<br/> <ol> <li>&nbsp;se farger mer nøyaktig</li> <li>&nbsp;fjerne farger for å gjøre det enklere å fokusere</li> </ol>"</string>
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"Overstyres av <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
- <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
- <skip />
- <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
- <skip />
+ <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> – Ladingen er satt på vent for å beskytte batteriet"</string>
+ <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> – Sjekker ladetilbehøret"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"Omtrent <xliff:g id="TIME_REMAINING">%1$s</xliff:g> igjen"</string>
<string name="power_discharging_duration" msgid="1076561255466053220">"Omtrent <xliff:g id="TIME_REMAINING">%1$s</xliff:g> igjen (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
<string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Omtrent <xliff:g id="TIME_REMAINING">%1$s</xliff:g> igjen basert på bruken din"</string>
@@ -489,12 +486,10 @@
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Lader trådløst"</string>
<string name="battery_info_status_charging_dock" msgid="8573274094093364791">"Lader"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Lader ikke"</string>
- <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
- <skip />
+ <string name="battery_info_status_not_charging" msgid="1103084691314264664">"Tilkoblet, men lader ikke"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Ladet"</string>
<string name="battery_info_status_full_charged" msgid="3536054261505567948">"Fulladet"</string>
- <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
- <skip />
+ <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"Ladingen er satt på vent"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Kontrollert av administratoren"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Kontrollert av en begrenset innstilling"</string>
<string name="disabled" msgid="8017887509554714950">"Slått av"</string>
diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml
index 3a7da74..377078d 100644
--- a/packages/SettingsLib/res/values-ne/strings.xml
+++ b/packages/SettingsLib/res/values-ne/strings.xml
@@ -154,8 +154,7 @@
<string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"छवि सम्बन्धी"</string>
<string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"हेडफोन"</string>
<string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"इनपुट सम्बन्धी बाह्य यन्त्र"</string>
- <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
- <skip />
+ <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"श्रवण यन्त्रहरू"</string>
<string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"ब्लुटुथ"</string>
<string name="accessibility_wifi_off" msgid="1195445715254137155">"Wi-Fi बन्द।"</string>
<string name="accessibility_no_wifi" msgid="5297119459491085771">"Wi-Fi जडान विच्छेद भयो।"</string>
@@ -457,10 +456,8 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"तपाईं रङ सच्याउने सुविधाका सहायताले निम्न कार्य गर्न सक्नुहुन्छ:<br/> <ol> <li>&nbsp;अझ सटीक तरिकाले रङहरू हेर्न</li> <li>&nbsp;फोकस गर्नका लागि रङहरू हटाउन</li> </ol>"</string>
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> द्वारा अधिरोहित"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
- <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
- <skip />
- <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
- <skip />
+ <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - ब्याट्री जोगाउन चार्जिङ होल्ड गरिएको छ"</string>
+ <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - चार्जिङ एक्सेसरीको जाँच गरिँदै छ"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"लगभग <xliff:g id="TIME_REMAINING">%1$s</xliff:g> बाँकी छ"</string>
<string name="power_discharging_duration" msgid="1076561255466053220">"लगभग <xliff:g id="TIME_REMAINING">%1$s</xliff:g> बाँकी छ (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
<string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"तपाईंको प्रयोगको आधारमा लगभग <xliff:g id="TIME_REMAINING">%1$s</xliff:g> बाँकी छ"</string>
@@ -489,12 +486,10 @@
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"वायरलेस तरिकाले चार्ज गरिँदै छ"</string>
<string name="battery_info_status_charging_dock" msgid="8573274094093364791">"चार्ज हुँदै छ"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"चार्ज भइरहेको छैन"</string>
- <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
- <skip />
+ <string name="battery_info_status_not_charging" msgid="1103084691314264664">"जोडिएको छ तर चार्ज गरिराखिएको छैन"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"चार्ज भयो"</string>
<string name="battery_info_status_full_charged" msgid="3536054261505567948">"पूर्ण रूपमा चार्ज भएको छ"</string>
- <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
- <skip />
+ <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"चार्जिङ होल्ड गरिएको छ"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"प्रशासकद्वारा नियन्त्रित"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"प्रतिबन्धित सेटिङले नियन्त्रण गरेको"</string>
<string name="disabled" msgid="8017887509554714950">"असक्षम पारियो"</string>
diff --git a/packages/SettingsLib/res/values-or/strings.xml b/packages/SettingsLib/res/values-or/strings.xml
index ea245c48..30bb050 100644
--- a/packages/SettingsLib/res/values-or/strings.xml
+++ b/packages/SettingsLib/res/values-or/strings.xml
@@ -154,8 +154,7 @@
<string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"ଇମେଜିଙ୍ଗ"</string>
<string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"ହେଡ୍ଫୋନ୍"</string>
<string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"ଇନ୍ପୁଟ୍ ଉପକରଣ"</string>
- <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
- <skip />
+ <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"ଶ୍ରବଣ ଯନ୍ତ୍ର"</string>
<string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"ବ୍ଲୁଟୁଥ"</string>
<string name="accessibility_wifi_off" msgid="1195445715254137155">"ୱାଇ-ଫାଇ ବନ୍ଦ।"</string>
<string name="accessibility_no_wifi" msgid="5297119459491085771">"ୱାଇଫାଇ ବିଚ୍ଛିନ୍ନ କରାଗଲା।"</string>
@@ -457,10 +456,8 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"ଆପଣ ଏସବୁ କରିବାକୁ ଚାହିଁଲେ ରଙ୍ଗ ସଂଶୋଧନ ଉପଯୋଗୀ ହୋଇପାରିବ:<br/> <ol> <li>&nbsp;ଆହୁରି ସଠିକ୍ ଭାବେ ରଙ୍ଗଗୁଡ଼ିକ ଦେଖିବା</li> <li>&nbsp;ଆପଣଙ୍କୁ ଫୋକସ କରିବାରେ ସାହାଯ୍ୟ କରିବା ପାଇଁ ରଙ୍ଗଗୁଡ଼ିକୁ କାଢ଼ିବା</li> </ol>"</string>
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> ଦ୍ୱାରା ଓଭର୍ରାଇଡ୍ କରାଯାଇଛି"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
- <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
- <skip />
- <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
- <skip />
+ <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - ବେଟେରୀକୁ ସୁରକ୍ଷିତ ରଖିବା ପାଇଁ ଚାର୍ଜିଂ ହୋଲ୍ଡରେ ଅଛି"</string>
+ <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - ଚାର୍ଜିଂ ଆକସେସୋରୀକୁ ଯାଞ୍ଚ କରାଯାଉଛି"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"ପାଖାପାଖି <xliff:g id="TIME_REMAINING">%1$s</xliff:g> ବଳକା ଅଛି"</string>
<string name="power_discharging_duration" msgid="1076561255466053220">"ପାଖାପାଖି <xliff:g id="TIME_REMAINING">%1$s</xliff:g> ପାଇଁ (<xliff:g id="LEVEL">%2$s</xliff:g>) ବଳକା ଅଛି"</string>
<string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"ଆପଣଙ୍କ ବ୍ୟବହାରକୁ ଆଧାର କରି ପାଖାପାଖି <xliff:g id="TIME_REMAINING">%1$s</xliff:g> ବଳକା ଅଛି"</string>
@@ -489,12 +486,10 @@
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"ୱେୟରଲେସ ଭାବେ ଚାର୍ଜିଂ"</string>
<string name="battery_info_status_charging_dock" msgid="8573274094093364791">"ଚାର୍ଜ ହେଉଛି"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"ଚାର୍ଜ ହେଉନାହିଁ"</string>
- <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
- <skip />
+ <string name="battery_info_status_not_charging" msgid="1103084691314264664">"କନେକ୍ଟ ହୋଇଛି, କିନ୍ତୁ ଚାର୍ଜ ହେଉନାହିଁ"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"ଚାର୍ଜ ହୋଇଯାଇଛି"</string>
<string name="battery_info_status_full_charged" msgid="3536054261505567948">"ସମ୍ପୂର୍ଣ୍ଣ ଭାବରେ ଚାର୍ଜ ହୋଇଛି"</string>
- <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
- <skip />
+ <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"ଚାର୍ଜିଂ ହୋଲ୍ଡରେ ଅଛି"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"ଆଡ୍ମିନ୍ ଦ୍ୱାରା ନିୟନ୍ତ୍ରିତ"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"ପ୍ରତିବନ୍ଧିତ ସେଟିଂ ଦ୍ୱାରା ନିୟନ୍ତ୍ରଣ କରାଯାଇଛି"</string>
<string name="disabled" msgid="8017887509554714950">"ଅକ୍ଷମ ହୋଇଛି"</string>
diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml
index 47c0f8a..d25b921 100644
--- a/packages/SettingsLib/res/values-pa/strings.xml
+++ b/packages/SettingsLib/res/values-pa/strings.xml
@@ -154,8 +154,7 @@
<string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"ਇਮੇਜਿੰਗ"</string>
<string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"ਹੈੱਡਫੋਨ"</string>
<string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"ਇਨਪੁੱਟ ਪੈਰਿਫੈਰਲ"</string>
- <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
- <skip />
+ <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"ਸੁਣਨ ਦੇ ਸਾਧਨ"</string>
<string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"ਬਲੂਟੁੱਥ"</string>
<string name="accessibility_wifi_off" msgid="1195445715254137155">"Wifi ਬੰਦ।"</string>
<string name="accessibility_no_wifi" msgid="5297119459491085771">"Wifi ਡਿਸਕਨੈਕਟ ਕੀਤਾ।"</string>
@@ -457,10 +456,8 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"ਰੰਗ ਸੁਧਾਈ ਉਦੋਂ ਲਾਹੇਵੰਦ ਹੋ ਸਕਦੀ ਹੈ, ਜਦੋਂ ਤੁਸੀਂ:<br/> <ol> <li>&nbsp;ਰੰਗਾਂ ਨੂੰ ਹੋਰ ਸਹੀ ਢੰਗ ਨਾਲ ਦੇਖਣਾ ਚਾਹੋ</li> <li>&nbsp;ਫੋਕਸ ਕਰਨ ਵਿੱਚ ਮਦਦ ਲਈ ਰੰਗ ਹਟਾਉਣਾ ਚਾਹੋ</li> </ol>"</string>
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> ਦੁਆਰਾ ਓਵਰਰਾਈਡ ਕੀਤਾ"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
- <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
- <skip />
- <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
- <skip />
+ <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - ਬੈਟਰੀ ਦੀ ਸੁਰੱਖਿਆ ਲਈ ਚਾਰਜਿੰਗ ਨੂੰ ਰੋਕਿਆ ਗਿਆ ਹੈ"</string>
+ <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - ਚਾਰਜਿੰਗ ਐਕਸੈਸਰੀ ਦੀ ਜਾਂਚ ਕੀਤੀ ਜਾ ਰਹੀ ਹੈ"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"ਲਗਭਗ <xliff:g id="TIME_REMAINING">%1$s</xliff:g> ਬਾਕੀ"</string>
<string name="power_discharging_duration" msgid="1076561255466053220">"ਲਗਭਗ <xliff:g id="TIME_REMAINING">%1$s</xliff:g> ਬਾਕੀ (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
<string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"ਤੁਹਾਡੀ ਵਰਤੋਂ ਦੇ ਆਧਾਰ \'ਤੇ ਲਗਭਗ <xliff:g id="TIME_REMAINING">%1$s</xliff:g> ਬਾਕੀ"</string>
@@ -489,12 +486,10 @@
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"ਬਿਨਾਂ ਤਾਰ ਤੋਂ ਚਾਰਜ ਹੋ ਰਹੀ ਹੈ"</string>
<string name="battery_info_status_charging_dock" msgid="8573274094093364791">"ਚਾਰਜ ਹੋ ਰਿਹਾ ਹੈ"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"ਚਾਰਜ ਨਹੀਂ ਹੋ ਰਿਹਾ"</string>
- <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
- <skip />
+ <string name="battery_info_status_not_charging" msgid="1103084691314264664">"ਕਨੈਕਟ ਹੋ ਗਿਆ, ਪਰ ਚਾਰਜ ਨਹੀਂ ਹੋ ਰਿਹਾ ਹੈ"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"ਚਾਰਜ ਹੋ ਗਈ"</string>
<string name="battery_info_status_full_charged" msgid="3536054261505567948">"ਪੂਰੀ ਚਾਰਜ ਹੋ ਗਈ ਹੈ"</string>
- <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
- <skip />
+ <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"ਚਾਰਜਿੰਗ ਨੂੰ ਰੋਕਿਆ ਗਿਆ ਹੈ"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"ਪ੍ਰਸ਼ਾਸਕ ਵੱਲੋਂ ਕੰਟਰੋਲ ਕੀਤੀ ਗਈ"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"ਪ੍ਰਤਿਬੰਧਿਤ ਸੈਟਿੰਗ ਰਾਹੀਂ ਕੰਟਰੋਲ ਕੀਤੀ ਜਾਂਦੀ ਹੈ"</string>
<string name="disabled" msgid="8017887509554714950">"ਅਯੋਗ ਬਣਾਇਆ"</string>
diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml
index a8ba18d..72a1b2c 100644
--- a/packages/SettingsLib/res/values-pl/strings.xml
+++ b/packages/SettingsLib/res/values-pl/strings.xml
@@ -154,8 +154,7 @@
<string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"Obrazowanie"</string>
<string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"Słuchawki"</string>
<string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"Peryferyjne urządzenie wejściowe"</string>
- <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
- <skip />
+ <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"Aparaty słuchowe"</string>
<string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"Bluetooth"</string>
<string name="accessibility_wifi_off" msgid="1195445715254137155">"Wi-Fi wyłączone."</string>
<string name="accessibility_no_wifi" msgid="5297119459491085771">"Wi-Fi odłączone."</string>
@@ -457,10 +456,8 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"Korekcja kolorów może być pomocna, gdy:<br/> <ol> <li>&nbsp;chcesz wyraźniej widzieć kolory;</li> <li>&nbsp;chcesz usunąć kolory, aby łatwiej było się skupić.</li> </ol>"</string>
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"Nadpisana przez <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
- <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
- <skip />
- <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
- <skip />
+ <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> – wstrzymano ładowanie, aby chronić baterię"</string>
+ <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> – sprawdzam akcesoria do ładowania"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"Jeszcze około <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
<string name="power_discharging_duration" msgid="1076561255466053220">"Jeszcze około <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
<string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Jeszcze około <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (na podstawie Twojego sposobu korzystania)"</string>
@@ -489,12 +486,10 @@
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Ładowanie bezprzewodowe"</string>
<string name="battery_info_status_charging_dock" msgid="8573274094093364791">"Ładowanie"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Nie podłączony"</string>
- <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
- <skip />
+ <string name="battery_info_status_not_charging" msgid="1103084691314264664">"Podłączono, ale nie ładuje się"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Naładowana"</string>
<string name="battery_info_status_full_charged" msgid="3536054261505567948">"Bateria w pełni naładowana"</string>
- <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
- <skip />
+ <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"Ładowanie wstrzymane"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Kontrolowane przez administratora"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Kontrolowane przez ograniczone ustawienia"</string>
<string name="disabled" msgid="8017887509554714950">"Wyłączone"</string>
diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml
index fef4378..def9d89 100644
--- a/packages/SettingsLib/res/values-ro/strings.xml
+++ b/packages/SettingsLib/res/values-ro/strings.xml
@@ -154,8 +154,7 @@
<string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"Dispozitiv pentru imagini"</string>
<string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"Căști"</string>
<string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"Dispozitiv periferic de intrare"</string>
- <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
- <skip />
+ <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"Aparate auditive"</string>
<string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"Bluetooth"</string>
<string name="accessibility_wifi_off" msgid="1195445715254137155">"Wi-Fi dezactivat."</string>
<string name="accessibility_no_wifi" msgid="5297119459491085771">"Wi-Fi deconectat."</string>
@@ -457,10 +456,8 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"Corecția culorii poate fi utilă dacă vrei:<br/> <ol> <li>&nbsp;să vezi mai precis culorile;</li> <li>&nbsp;să elimini culorile pentru a te concentra mai bine.</li> </ol>"</string>
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"Valoare înlocuită de <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
- <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
- <skip />
- <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
- <skip />
+ <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> – Încărcarea s-a întrerupt pentru a proteja bateria"</string>
+ <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> – Se verifică accesoriul de încărcare"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"Timp aproximativ rămas: <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
<string name="power_discharging_duration" msgid="1076561255466053220">"Timp aproximativ rămas: <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
<string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"În baza utilizării, timpul rămas este de aproximativ <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -489,12 +486,10 @@
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Se încarcă wireless"</string>
<string name="battery_info_status_charging_dock" msgid="8573274094093364791">"Se încarcă"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Nu se încarcă"</string>
- <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
- <skip />
+ <string name="battery_info_status_not_charging" msgid="1103084691314264664">"Conectat, dar nu se încarcă"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Încărcată"</string>
<string name="battery_info_status_full_charged" msgid="3536054261505567948">"Complet încărcată"</string>
- <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
- <skip />
+ <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"Încărcare întreruptă"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Controlată de administrator"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Controlată de setarea restricționată"</string>
<string name="disabled" msgid="8017887509554714950">"Dezactivată"</string>
diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
index 5989e2a..5cc1a5b 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -154,8 +154,7 @@
<string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"Камера"</string>
<string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"Наушники"</string>
<string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"Периферийное устройство ввода"</string>
- <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
- <skip />
+ <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"Слуховые аппараты"</string>
<string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"Bluetooth"</string>
<string name="accessibility_wifi_off" msgid="1195445715254137155">"Wi-Fi выключен"</string>
<string name="accessibility_no_wifi" msgid="5297119459491085771">"Wi-Fi отключен"</string>
@@ -457,10 +456,8 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"Используйте коррекцию цвета, чтобы:<br/> <ol> <li> Добиться нужной цветопередачи.</li> <li> Убрать цвета, которые мешают сосредоточиться.</li> </ol>"</string>
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"Новая настройка: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"Уровень заряда – <xliff:g id="PERCENTAGE">%1$s</xliff:g>. <xliff:g id="TIME_STRING">%2$s</xliff:g>."</string>
- <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
- <skip />
- <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
- <skip />
+ <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g>, зарядка приостановлена для защиты батареи"</string>
+ <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g>, проверяется зарядное устройство"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"Заряда хватит примерно на <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
<string name="power_discharging_duration" msgid="1076561255466053220">"Заряда (<xliff:g id="LEVEL">%2$s</xliff:g>) хватит примерно на <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
<string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Заряда хватит примерно на <xliff:g id="TIME_REMAINING">%1$s</xliff:g> при текущем уровне расхода"</string>
@@ -489,12 +486,10 @@
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Беспроводная зарядка"</string>
<string name="battery_info_status_charging_dock" msgid="8573274094093364791">"Зарядка"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Не заряжается"</string>
- <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
- <skip />
+ <string name="battery_info_status_not_charging" msgid="1103084691314264664">"Устройство подключено, но не заряжается"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Батарея заряжена"</string>
<string name="battery_info_status_full_charged" msgid="3536054261505567948">"Батарея заряжена"</string>
- <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
- <skip />
+ <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"Зарядка приостановлена"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Контролируется администратором"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Контролируется настройками с ограниченным доступом"</string>
<string name="disabled" msgid="8017887509554714950">"Отключено"</string>
diff --git a/packages/SettingsLib/res/values-si/strings.xml b/packages/SettingsLib/res/values-si/strings.xml
index 5c3243b..0d9ca37 100644
--- a/packages/SettingsLib/res/values-si/strings.xml
+++ b/packages/SettingsLib/res/values-si/strings.xml
@@ -154,8 +154,7 @@
<string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"නිරූපණය"</string>
<string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"හෙඩ්ෆෝන්"</string>
<string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"ආදාන උපාංග"</string>
- <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
- <skip />
+ <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"ශ්රවණාධාරක"</string>
<string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"බ්ලූටූත්"</string>
<string name="accessibility_wifi_off" msgid="1195445715254137155">"Wifi අක්රියයි."</string>
<string name="accessibility_no_wifi" msgid="5297119459491085771">"Wifi සම්බන්ධ කර නොමැත."</string>
@@ -457,10 +456,8 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"ඔබට පහත දේවල් සිදු කිරීම අවශ්ය විට වර්ණ නිවැරදි කිරීම ප්රයෝජනවත් විය හැකිය:<br/> <ol> <li>වඩාත් නිවැරදිව වර්ණ දැකීම</li> <li>ඔබට අවධානය යොමු කිරීමට උදවු වීමට වර්ණ ඉවත් කිරීම</li> </ol>"</string>
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> මගින් ඉක්මවන ලදී"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
- <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
- <skip />
- <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
- <skip />
+ <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - බැටරිය ආරක්ෂා කිරීම සඳහා ආරෝපණය රඳවා තබා ඇත"</string>
+ <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - ආරෝපණ ආයිත්තම පරීක්ෂා කිරීම"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g> ක් පමණ ඉතිරියි"</string>
<string name="power_discharging_duration" msgid="1076561255466053220">"<xliff:g id="TIME_REMAINING">%1$s</xliff:g> ක් පමණ ඉතිරියි (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
<string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"ඔබේ භාවිතය මත පදනම්ව <xliff:g id="TIME_REMAINING">%1$s</xliff:g> පමණ ඉතිරිව ඇත"</string>
@@ -489,12 +486,10 @@
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"නොරැහැන්ව ආරෝපණය වේ"</string>
<string name="battery_info_status_charging_dock" msgid="8573274094093364791">"ආරෝපණය වේ"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"ආරෝපණය නොවේ"</string>
- <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
- <skip />
+ <string name="battery_info_status_not_charging" msgid="1103084691314264664">"සම්බන්ධයි, නමුත් ආරෝපණය නොවේ"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"අරෝපිතයි"</string>
<string name="battery_info_status_full_charged" msgid="3536054261505567948">"සම්පූර්ණයෙන් ආරෝපණ වී ඇත"</string>
- <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
- <skip />
+ <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"ආරෝපණය රදවාගෙන ඇත"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"පරිපාලක විසින් පාලනය කරන ලදී"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"සීමා කළ සැකසීම මගින් පාලනය වේ"</string>
<string name="disabled" msgid="8017887509554714950">"අබල කර ඇත"</string>
diff --git a/packages/SettingsLib/res/values-sq/strings.xml b/packages/SettingsLib/res/values-sq/strings.xml
index d9fe738..a722ad1 100644
--- a/packages/SettingsLib/res/values-sq/strings.xml
+++ b/packages/SettingsLib/res/values-sq/strings.xml
@@ -154,8 +154,7 @@
<string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"Imazhe"</string>
<string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"Kufje"</string>
<string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"Hyrje periferike"</string>
- <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
- <skip />
+ <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"Aparatet e dëgjimit"</string>
<string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"Bluetooth-i"</string>
<string name="accessibility_wifi_off" msgid="1195445715254137155">"Wi-Fi është çaktivizuar."</string>
<string name="accessibility_no_wifi" msgid="5297119459491085771">"Wi-Fi është i shkëputur."</string>
@@ -457,10 +456,8 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"Korrigjimi i ngjyrës mund të jetë i dobishëm kur dëshiron:<br/> <ol> <li>&nbsp;Të shohësh ngjyrat më saktë</li> <li>&nbsp;Të heqësh ngjyrat për të të ndihmuar të fokusohesh</li> </ol>"</string>
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"Mbivendosur nga <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
- <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
- <skip />
- <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
- <skip />
+ <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - Karikimi është vendosur në pritje për të mbrojtur baterinë"</string>
+ <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - Po kontrollohet aksesori i karikimit"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"Rreth <xliff:g id="TIME_REMAINING">%1$s</xliff:g> të mbetura"</string>
<string name="power_discharging_duration" msgid="1076561255466053220">"Rreth <xliff:g id="TIME_REMAINING">%1$s</xliff:g> të mbetura (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
<string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Rreth <xliff:g id="TIME_REMAINING">%1$s</xliff:g> të mbetura bazuar në përdorimin tënd"</string>
@@ -489,12 +486,10 @@
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Po karikohet wireless"</string>
<string name="battery_info_status_charging_dock" msgid="8573274094093364791">"Po karikohet"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Nuk po karikohet"</string>
- <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
- <skip />
+ <string name="battery_info_status_not_charging" msgid="1103084691314264664">"Është lidhur, por nuk po karikohet"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Karikuar"</string>
<string name="battery_info_status_full_charged" msgid="3536054261505567948">"Karikuar plotësisht"</string>
- <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
- <skip />
+ <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"Karikimi në pritje"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Kontrolluar nga administratori"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Kontrollohet nga \"Cilësimet e kufizuara\""</string>
<string name="disabled" msgid="8017887509554714950">"Çaktivizuar"</string>
diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml
index 042fc34..66e448b 100644
--- a/packages/SettingsLib/res/values-sr/strings.xml
+++ b/packages/SettingsLib/res/values-sr/strings.xml
@@ -154,8 +154,7 @@
<string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"Обрада слика"</string>
<string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"Слушалице"</string>
<string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"Периферни уређај за унос"</string>
- <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
- <skip />
+ <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"Слушни апарати"</string>
<string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"Bluetooth"</string>
<string name="accessibility_wifi_off" msgid="1195445715254137155">"WiFi је искључен."</string>
<string name="accessibility_no_wifi" msgid="5297119459491085771">"WiFi веза је прекинута."</string>
@@ -457,10 +456,8 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"Корекција боја може да буде корисна када желите:<br/> <ol> <li>&nbsp;Прецизније да видите боје</li> <li>&nbsp;Да уклоните боје како бисте се фокусирали</li> </ol>"</string>
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"Замењује га <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g>–<xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
- <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
- <skip />
- <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
- <skip />
+ <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> – пуњење је на чекању да би се заштитила батерија"</string>
+ <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> – провера додатне опреме за пуњење"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"Преостало је око <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
<string name="power_discharging_duration" msgid="1076561255466053220">"Преостало је око <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
<string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Преостало је око <xliff:g id="TIME_REMAINING">%1$s</xliff:g> на основу коришћења"</string>
@@ -489,12 +486,10 @@
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Бежично пуњење"</string>
<string name="battery_info_status_charging_dock" msgid="8573274094093364791">"Пуњење"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Не пуни се"</string>
- <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
- <skip />
+ <string name="battery_info_status_not_charging" msgid="1103084691314264664">"Уређај је повезан, али се не пуни"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Напуњено"</string>
<string name="battery_info_status_full_charged" msgid="3536054261505567948">"Напуњено до краја"</string>
- <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
- <skip />
+ <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"Пуњење је на чекању"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Контролише администратор"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Контролишу ограничена подешавања"</string>
<string name="disabled" msgid="8017887509554714950">"Онемогућено"</string>
diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
index 1f103e8ad..82567bf 100644
--- a/packages/SettingsLib/res/values-sv/strings.xml
+++ b/packages/SettingsLib/res/values-sv/strings.xml
@@ -154,8 +154,7 @@
<string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"Bild"</string>
<string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"Hörlur"</string>
<string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"Inmatning från kringutrustning"</string>
- <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
- <skip />
+ <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"Hörapparater"</string>
<string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"Bluetooth"</string>
<string name="accessibility_wifi_off" msgid="1195445715254137155">"Wifi är inaktiverat."</string>
<string name="accessibility_no_wifi" msgid="5297119459491085771">"Ingen wifi-anslutning."</string>
@@ -457,10 +456,8 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"Färgkorrigering kan vara bra för att<br/> <ol> <li>&nbsp;urskilja färger bättre</li> <li>&nbsp;ta bort färger som distraherar</li> </ol>"</string>
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"Har åsidosatts av <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
- <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
- <skip />
- <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
- <skip />
+ <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - Laddningen har pausats för att skydda batteriet"</string>
+ <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - Kontrollerar laddningstillbehöret"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"Cirka <xliff:g id="TIME_REMAINING">%1$s</xliff:g> kvar"</string>
<string name="power_discharging_duration" msgid="1076561255466053220">"Cirka <xliff:g id="TIME_REMAINING">%1$s</xliff:g> kvar (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
<string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Cirka <xliff:g id="TIME_REMAINING">%1$s</xliff:g> kvar utifrån din användning"</string>
@@ -489,12 +486,10 @@
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Laddas trådlöst"</string>
<string name="battery_info_status_charging_dock" msgid="8573274094093364791">"Laddas"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Laddar inte"</string>
- <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
- <skip />
+ <string name="battery_info_status_not_charging" msgid="1103084691314264664">"Ansluten men laddas inte"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Laddat"</string>
<string name="battery_info_status_full_charged" msgid="3536054261505567948">"Fulladdad"</string>
- <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
- <skip />
+ <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"Laddningen har pausats"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Strys av administratören"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Styrs av spärrad inställning"</string>
<string name="disabled" msgid="8017887509554714950">"Inaktiverad"</string>
diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml
index 21e7bf3..a5ce169 100644
--- a/packages/SettingsLib/res/values-ta/strings.xml
+++ b/packages/SettingsLib/res/values-ta/strings.xml
@@ -154,8 +154,7 @@
<string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"இமேஜிங்"</string>
<string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"ஹெட்ஃபோன்"</string>
<string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"இன்புட் பெரிபெரல்"</string>
- <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
- <skip />
+ <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"செவித்துணைக் கருவிகள்"</string>
<string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"புளூடூத்"</string>
<string name="accessibility_wifi_off" msgid="1195445715254137155">"வைஃபை முடக்கப்பட்டது."</string>
<string name="accessibility_no_wifi" msgid="5297119459491085771">"வைஃபை துண்டிக்கப்பட்டது."</string>
@@ -180,7 +179,7 @@
<string name="running_process_item_user_label" msgid="3988506293099805796">"பயனர்: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
<string name="launch_defaults_some" msgid="3631650616557252926">"சில இயல்புநிலைகள் அமைக்கப்பட்டன"</string>
<string name="launch_defaults_none" msgid="8049374306261262709">"இயல்புநிலைகள் எதுவும் அமைக்கப்படவில்லை"</string>
- <string name="tts_settings" msgid="8130616705989351312">"உரை வடிவத்திலிருந்து பேச்சுக்கான அமைப்பு"</string>
+ <string name="tts_settings" msgid="8130616705989351312">"\'எழுத்திலிருந்து பேச்சு\' அமைப்புகள்"</string>
<string name="tts_settings_title" msgid="7602210956640483039">"உரையிலிருந்து பேச்சாக மாற்றுதல்"</string>
<string name="tts_default_rate_title" msgid="3964187817364304022">"பேச்சு வீதம்"</string>
<string name="tts_default_rate_summary" msgid="3781937042151716987">"பேசப்படும் உரையின் வேகம்"</string>
@@ -457,10 +456,8 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"நீங்கள் இவற்றைச் செய்ய விரும்பும்போது கலர் கரெக்ஷன் உதவும்:<br/> <ol> <li>&nbsp;வண்ணங்களை மிகத் துல்லியமாகப் பார்த்தல்</li> <li>&nbsp;கவனம் செலுத்துவதற்கு உதவ வண்ணங்களை அகற்றுதல்</li> </ol>"</string>
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> மூலம் மேலெழுதப்பட்டது"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
- <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
- <skip />
- <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
- <skip />
+ <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - பேட்டரியைப் பாதுகாப்பதற்காகச் சார்ஜிங் இடைநிறுத்தப்பட்டுள்ளது"</string>
+ <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - சார்ஜிங் துணைக்கருவியைச் சரிபார்க்கிறது"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"கிட்டத்தட்ட <xliff:g id="TIME_REMAINING">%1$s</xliff:g> மீதமுள்ளது"</string>
<string name="power_discharging_duration" msgid="1076561255466053220">"கிட்டத்தட்ட <xliff:g id="TIME_REMAINING">%1$s</xliff:g> மீதமுள்ளது (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
<string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"உபயோகத்தின் அடிப்படையில் கிட்டத்தட்ட <xliff:g id="TIME_REMAINING">%1$s</xliff:g> மீதமுள்ளது"</string>
@@ -489,12 +486,10 @@
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"வயரின்றி சார்ஜாகிறது"</string>
<string name="battery_info_status_charging_dock" msgid="8573274094093364791">"சார்ஜாகிறது"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"சார்ஜ் செய்யப்படவில்லை"</string>
- <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
- <skip />
+ <string name="battery_info_status_not_charging" msgid="1103084691314264664">"இணைக்கப்பட்டது. ஆனால் சார்ஜ் ஆகவில்லை"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"சார்ஜாகிவிட்டது"</string>
<string name="battery_info_status_full_charged" msgid="3536054261505567948">"முழுவதும் சார்ஜாகிவிட்டது"</string>
- <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
- <skip />
+ <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"சார்ஜிங் இடைநிறுத்தப்பட்டுள்ளது"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"நிர்வாகி கட்டுப்படுத்துகிறார்"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"வரையறுக்கப்பட்ட அமைப்பால் கட்டுப்படுத்தப்படுகிறது"</string>
<string name="disabled" msgid="8017887509554714950">"முடக்கப்பட்டது"</string>
diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml
index f32a14a..53f75cb 100644
--- a/packages/SettingsLib/res/values-tl/strings.xml
+++ b/packages/SettingsLib/res/values-tl/strings.xml
@@ -154,8 +154,7 @@
<string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"Imaging"</string>
<string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"Headphone"</string>
<string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"Input Peripheral"</string>
- <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
- <skip />
+ <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"Mga Hearing Aid"</string>
<string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"Bluetooth"</string>
<string name="accessibility_wifi_off" msgid="1195445715254137155">"Naka-off ang Wifi."</string>
<string name="accessibility_no_wifi" msgid="5297119459491085771">"Nakadiskonekta ang Wifi."</string>
@@ -457,10 +456,8 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"Puwedeng makatulong ang pagtatama ng kulay kapag gusto mong:<br/> <ol> <li>&nbsp;Makita nang mas tumpak ang mga kulay</li> <li>&nbsp;Alisin ang mga kulay para matulungan kang tumuon</li> </ol>"</string>
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"Na-override ng <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
- <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
- <skip />
- <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
- <skip />
+ <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - Naka-hold ang pag-charge para protektahan ang baterya"</string>
+ <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - Sinusuri ang accessory sa pag-charge"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"Humigit-kumulang <xliff:g id="TIME_REMAINING">%1$s</xliff:g> ang natitira"</string>
<string name="power_discharging_duration" msgid="1076561255466053220">"Humigit-kumulang <xliff:g id="TIME_REMAINING">%1$s</xliff:g> ang natitira (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
<string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Humigit-kumulang <xliff:g id="TIME_REMAINING">%1$s</xliff:g> ang natitira batay sa iyong paggamit"</string>
@@ -489,12 +486,10 @@
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Wireless na nagcha-charge"</string>
<string name="battery_info_status_charging_dock" msgid="8573274094093364791">"Nagcha-charge"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Hindi nagcha-charge"</string>
- <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
- <skip />
+ <string name="battery_info_status_not_charging" msgid="1103084691314264664">"Nakakonekta, pero hindi nagcha-charge"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Charged"</string>
<string name="battery_info_status_full_charged" msgid="3536054261505567948">"Puno ang Baterya"</string>
- <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
- <skip />
+ <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"Naka-hold ang pag-charge"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Pinapamahalaan ng admin"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Kinokontrol ng Pinaghihigpitang Setting"</string>
<string name="disabled" msgid="8017887509554714950">"Naka-disable"</string>
diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
index 06e9729..8e491a1 100644
--- a/packages/SettingsLib/res/values-tr/strings.xml
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -154,8 +154,7 @@
<string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"Görüntüleme"</string>
<string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"Kulaklık"</string>
<string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"Giriş Çevre Birimi"</string>
- <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
- <skip />
+ <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"İşitme Cihazları"</string>
<string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"Bluetooth"</string>
<string name="accessibility_wifi_off" msgid="1195445715254137155">"Kablosuz kapalı."</string>
<string name="accessibility_no_wifi" msgid="5297119459491085771">"Kablosuz bağlantı kesildi."</string>
@@ -457,10 +456,8 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"Renk düzeltme aşağıdaki durumlarda faydalı olabilir:<br/> <ol> <li>&nbsp;Renkleri daha doğru görmek istediğinizde</li> <li>&nbsp;Odaklanmak için renkleri kaldırmak istediğinizde</li> </ol>"</string>
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> tarafından geçersiz kılındı"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
- <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
- <skip />
- <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
- <skip />
+ <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - Pili korumak için şarj beklemede"</string>
+ <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - Şarj aksesuarı kontrol ediliyor"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"Yaklaşık <xliff:g id="TIME_REMAINING">%1$s</xliff:g> kaldı"</string>
<string name="power_discharging_duration" msgid="1076561255466053220">"Yaklaşık <xliff:g id="TIME_REMAINING">%1$s</xliff:g> kaldı (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
<string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Kullanımınıza dayalı olarak yaklaşık <xliff:g id="TIME_REMAINING">%1$s</xliff:g> kaldı"</string>
@@ -489,12 +486,10 @@
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Kablosuz şarj oluyor"</string>
<string name="battery_info_status_charging_dock" msgid="8573274094093364791">"Şarj Etme"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Şarj olmuyor"</string>
- <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
- <skip />
+ <string name="battery_info_status_not_charging" msgid="1103084691314264664">"Bağlı ancak şarj olmuyor"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Şarj oldu"</string>
<string name="battery_info_status_full_charged" msgid="3536054261505567948">"Pilin Şarjı Tam"</string>
- <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
- <skip />
+ <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"Şarj işlemi beklemede"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Yönetici tarafından denetleniyor"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Kısıtlanmış ayar tarafından kontrol ediliyor"</string>
<string name="disabled" msgid="8017887509554714950">"Devre dışı"</string>
diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml
index cd00e17..45ed508 100644
--- a/packages/SettingsLib/res/values-uk/strings.xml
+++ b/packages/SettingsLib/res/values-uk/strings.xml
@@ -154,8 +154,7 @@
<string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"Візуалізація"</string>
<string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"Навушники"</string>
<string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"Периферійне введення"</string>
- <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
- <skip />
+ <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"Слухові апарати"</string>
<string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"Bluetooth"</string>
<string name="accessibility_wifi_off" msgid="1195445715254137155">"Wi-Fi вимкнено."</string>
<string name="accessibility_no_wifi" msgid="5297119459491085771">"Wi-Fi від’єднано."</string>
@@ -457,10 +456,8 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"Корекція кольору корисна, якщо ви хочете:<br/> <ol> <li>&nbsp;точніше бачити кольори;</li> <li>&nbsp;вилучити кольори, щоб легше зосереджуватися.</li> </ol>"</string>
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"Замінено на <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
- <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
- <skip />
- <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
- <skip />
+ <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> – заряджання призупинено, щоб захистити акумулятор"</string>
+ <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> – перевірка зарядного пристрою"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"Залишилося приблизно <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
<string name="power_discharging_duration" msgid="1076561255466053220">"Залишилося приблизно <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
<string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Згідно з даними про використання залишилося приблизно <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -489,12 +486,10 @@
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Бездротове заряджання"</string>
<string name="battery_info_status_charging_dock" msgid="8573274094093364791">"Заряджання"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Не заряджається"</string>
- <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
- <skip />
+ <string name="battery_info_status_not_charging" msgid="1103084691314264664">"Пристрій підключено, але він не заряджається"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Заряджено"</string>
<string name="battery_info_status_full_charged" msgid="3536054261505567948">"Повністю заряджено"</string>
- <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
- <skip />
+ <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"Заряджання призупинено"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Керується адміністратором"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Керується налаштуваннями з обмеженнями"</string>
<string name="disabled" msgid="8017887509554714950">"Вимкнено"</string>
diff --git a/packages/SettingsLib/res/values-uz/strings.xml b/packages/SettingsLib/res/values-uz/strings.xml
index 3acb9cd..b46fca5 100644
--- a/packages/SettingsLib/res/values-uz/strings.xml
+++ b/packages/SettingsLib/res/values-uz/strings.xml
@@ -154,8 +154,7 @@
<string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"Kamera"</string>
<string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"Quloqchin"</string>
<string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"Kiritish qurilmasi"</string>
- <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
- <skip />
+ <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"Eshitish moslamalari"</string>
<string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"Bluetooth"</string>
<string name="accessibility_wifi_off" msgid="1195445715254137155">"Wi-Fi o‘chiq."</string>
<string name="accessibility_no_wifi" msgid="5297119459491085771">"Wi-Fi o‘chiq."</string>
@@ -457,10 +456,8 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"Ranglarni tuzatishning foydasi:<br/> <ol> <li>&nbsp;Ranglar yanada aniqroq koʻrinadi</li> <li>&nbsp;Diqqatni qaratish uchun ortiqcha ranglarni olib tashlash imkonini beradi</li> </ol>"</string>
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"<xliff:g id="TITLE">%1$s</xliff:g> bilan almashtirildi"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> – <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
- <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
- <skip />
- <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
- <skip />
+ <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - Batareyani himoyalash uchun quvvatlash toʻxtatildi"</string>
+ <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - Quvvatlash aksessuari tekshirilmoqda"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"Taxminan <xliff:g id="TIME_REMAINING">%1$s</xliff:g> qoldi"</string>
<string name="power_discharging_duration" msgid="1076561255466053220">"Taxminan <xliff:g id="TIME_REMAINING">%1$s</xliff:g> qoldi (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
<string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Quvvati tugashiga taxminan <xliff:g id="TIME_REMAINING">%1$s</xliff:g> qoldi"</string>
@@ -489,12 +486,10 @@
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Simsiz quvvat olmoqda"</string>
<string name="battery_info_status_charging_dock" msgid="8573274094093364791">"Quvvat olmoqda"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Quvvat olmayapti"</string>
- <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
- <skip />
+ <string name="battery_info_status_not_charging" msgid="1103084691314264664">"Ulangan, lekin quvvat olmayapti"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Quvvat oldi"</string>
<string name="battery_info_status_full_charged" msgid="3536054261505567948">"Toʻliq quvvatlandi"</string>
- <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
- <skip />
+ <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"Quvvatlash toʻxtatildi"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Administrator tomonidan boshqariladi"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Cheklangan sozlama tomonidan boshqariladi"</string>
<string name="disabled" msgid="8017887509554714950">"Oʻchiq"</string>
diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml
index fcc049d..c471546 100644
--- a/packages/SettingsLib/res/values-vi/strings.xml
+++ b/packages/SettingsLib/res/values-vi/strings.xml
@@ -154,8 +154,7 @@
<string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"Tạo ảnh"</string>
<string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"Tai nghe"</string>
<string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"Thiết bị ngoại vi vào"</string>
- <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
- <skip />
+ <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"Thiết bị trợ thính"</string>
<string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"Bluetooth"</string>
<string name="accessibility_wifi_off" msgid="1195445715254137155">"Đã tắt Wi-Fi."</string>
<string name="accessibility_no_wifi" msgid="5297119459491085771">"Đã ngắt kết nối Wi-Fi."</string>
@@ -457,10 +456,8 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"Tính năng chỉnh màu có thể giúp ích khi bạn muốn:<br/> <ol> <li>&nbsp;Thấy màu sắc chính xác hơn</li> <li>&nbsp;Loại bỏ bớt màu để tập trung</li> </ol>"</string>
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"Bị ghi đè bởi <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
- <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
- <skip />
- <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
- <skip />
+ <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> – Đang tạm ngưng sạc để bảo vệ pin"</string>
+ <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> – Đang kiểm tra phụ kiện sạc"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"Còn khoảng <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
<string name="power_discharging_duration" msgid="1076561255466053220">"Còn khoảng <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
<string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"Còn khoảng <xliff:g id="TIME_REMAINING">%1$s</xliff:g> dựa trên mức sử dụng của bạn"</string>
@@ -489,12 +486,10 @@
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Đang sạc không dây"</string>
<string name="battery_info_status_charging_dock" msgid="8573274094093364791">"Đang sạc"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Hiện không sạc"</string>
- <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
- <skip />
+ <string name="battery_info_status_not_charging" msgid="1103084691314264664">"Đã kết nối, nhưng không sạc"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"Đã sạc"</string>
<string name="battery_info_status_full_charged" msgid="3536054261505567948">"Đã sạc đầy"</string>
- <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
- <skip />
+ <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"Đang tạm ngưng sạc"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"Do quản trị viên kiểm soát"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"Do chế độ Cài đặt hạn chế kiểm soát"</string>
<string name="disabled" msgid="8017887509554714950">"Đã tắt"</string>
diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
index babcc07..e9774e1 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -456,7 +456,7 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"“色彩校正”功能适用于以下情况:<br/> <ol> <li>您想更准确地查看颜色</li> <li>您想移除颜色以提高专注程度</li> </ol>"</string>
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"已被“<xliff:g id="TITLE">%1$s</xliff:g>”覆盖"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
- <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - 为保护电池,充电已暂停"</string>
+ <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - 为保护电池,已暂停充电"</string>
<string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - 正在检查充电配件"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"大约还可使用<xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
<string name="power_discharging_duration" msgid="1076561255466053220">"大约还可使用<xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
@@ -489,7 +489,7 @@
<string name="battery_info_status_not_charging" msgid="1103084691314264664">"已连接,但未充电"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"已充满电"</string>
<string name="battery_info_status_full_charged" msgid="3536054261505567948">"已充满电"</string>
- <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"目前暂停充电"</string>
+ <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"充电已暂停"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"由管理员控制"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"由受限设置控制"</string>
<string name="disabled" msgid="8017887509554714950">"已停用"</string>
diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml
index 390ae37..1e3394d 100644
--- a/packages/SettingsLib/res/values-zh-rHK/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml
@@ -154,8 +154,7 @@
<string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"映像設備"</string>
<string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"耳機"</string>
<string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"輸入周邊設備"</string>
- <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
- <skip />
+ <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"助聽器"</string>
<string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"藍牙"</string>
<string name="accessibility_wifi_off" msgid="1195445715254137155">"Wi-Fi 已關閉。"</string>
<string name="accessibility_no_wifi" msgid="5297119459491085771">"Wi-Fi 連線已中斷。"</string>
@@ -457,10 +456,8 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"「色彩校正」功能適用於以下情況::<br/> <ol> <li>&nbsp;你想讓裝置顯示更準確的色彩</li> <li>&nbsp;你想移除色彩以提高專注力</li> </ol>"</string>
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"已由「<xliff:g id="TITLE">%1$s</xliff:g>」覆寫"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
- <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
- <skip />
- <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
- <skip />
+ <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - 為保護電池,目前暫停充電"</string>
+ <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - 正在檢查充電配件"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"還有大約 <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
<string name="power_discharging_duration" msgid="1076561255466053220">"還有大約 <xliff:g id="TIME_REMAINING">%1$s</xliff:g> (<xliff:g id="LEVEL">%2$s</xliff:g>)"</string>
<string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"根據你的使用情況,還有大約 <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -489,12 +486,10 @@
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"無線充電中"</string>
<string name="battery_info_status_charging_dock" msgid="8573274094093364791">"正在充電"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"非充電中"</string>
- <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
- <skip />
+ <string name="battery_info_status_not_charging" msgid="1103084691314264664">"已連接,但未充電"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"已充滿電"</string>
<string name="battery_info_status_full_charged" msgid="3536054261505567948">"充電完成"</string>
- <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
- <skip />
+ <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"目前暫停充電"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"已由管理員停用"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"由「受限設定」控制"</string>
<string name="disabled" msgid="8017887509554714950">"已停用"</string>
diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml
index 5f4b9ed..8643fde 100644
--- a/packages/SettingsLib/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml
@@ -154,8 +154,7 @@
<string name="bluetooth_talkback_imaging" msgid="8781682986822514331">"顯像裝置"</string>
<string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"頭戴式耳機"</string>
<string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"周邊輸入裝置"</string>
- <!-- no translation found for bluetooth_talkback_hearing_aids (3983279945542595479) -->
- <skip />
+ <string name="bluetooth_talkback_hearing_aids" msgid="3983279945542595479">"助聽器"</string>
<string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"藍牙"</string>
<string name="accessibility_wifi_off" msgid="1195445715254137155">"已關閉 Wi-Fi。"</string>
<string name="accessibility_no_wifi" msgid="5297119459491085771">"Wi-Fi 連線已中斷。"</string>
@@ -457,10 +456,8 @@
<string name="accessibility_display_daltonizer_preference_subtitle" msgid="1522101114585266455">"「色彩校正」功能適用於以下情況:<br/> <ol> <li>&nbsp;你想讓裝置顯示更準確的色彩</li> <li>&nbsp;你想移除色彩以提升專注力</li> </ol>"</string>
<string name="daltonizer_type_overridden" msgid="4509604753672535721">"已改為<xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="power_remaining_settings_home_page" msgid="4885165789445462557">"<xliff:g id="PERCENTAGE">%1$s</xliff:g> - <xliff:g id="TIME_STRING">%2$s</xliff:g>"</string>
- <!-- no translation found for power_charging_on_hold_settings_home_page (7690464049464805856) -->
- <skip />
- <!-- no translation found for power_incompatible_charging_settings_home_page (1261756225093962684) -->
- <skip />
+ <string name="power_charging_on_hold_settings_home_page" msgid="7690464049464805856">"<xliff:g id="LEVEL">%1$s</xliff:g> - 為保護電池,目前暫停充電"</string>
+ <string name="power_incompatible_charging_settings_home_page" msgid="1261756225093962684">"<xliff:g id="LEVEL">%1$s</xliff:g> - 正在檢查充電配件"</string>
<string name="power_remaining_duration_only" msgid="8264199158671531431">"還能使用約 <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
<string name="power_discharging_duration" msgid="1076561255466053220">"目前電量為 <xliff:g id="LEVEL">%2$s</xliff:g>,還能使用約 <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
<string name="power_remaining_duration_only_enhanced" msgid="2527842780666073218">"根據你的使用情形,還能使用約 <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
@@ -489,12 +486,10 @@
<string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"正在進行無線充電"</string>
<string name="battery_info_status_charging_dock" msgid="8573274094093364791">"充電中"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"非充電中"</string>
- <!-- no translation found for battery_info_status_not_charging (1103084691314264664) -->
- <skip />
+ <string name="battery_info_status_not_charging" msgid="1103084691314264664">"已連接,但未充電"</string>
<string name="battery_info_status_full" msgid="1339002294876531312">"充電完成"</string>
<string name="battery_info_status_full_charged" msgid="3536054261505567948">"充電完成"</string>
- <!-- no translation found for battery_info_status_charging_on_hold (6364355145521694438) -->
- <skip />
+ <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"目前暫停充電"</string>
<string name="disabled_by_admin_summary_text" msgid="5343911767402923057">"已由管理員停用"</string>
<string name="disabled_by_app_ops_text" msgid="8373595926549098012">"由限制設定控管"</string>
<string name="disabled" msgid="8017887509554714950">"已停用"</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/volume/data/repository/AudioRepository.kt b/packages/SettingsLib/src/com/android/settingslib/volume/data/repository/AudioRepository.kt
new file mode 100644
index 0000000..3355fb3
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/volume/data/repository/AudioRepository.kt
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.volume.data.repository
+
+import android.media.AudioManager
+import com.android.internal.util.ConcurrentUtils
+import kotlin.coroutines.CoroutineContext
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.callbackFlow
+import kotlinx.coroutines.flow.flowOn
+import kotlinx.coroutines.flow.stateIn
+import kotlinx.coroutines.launch
+
+/** Provides audio managing functionality and data. */
+interface AudioRepository {
+
+ /** Current [AudioManager.getMode]. */
+ val mode: StateFlow<Int>
+}
+
+class AudioRepositoryImpl(
+ private val audioManager: AudioManager,
+ backgroundCoroutineContext: CoroutineContext,
+ coroutineScope: CoroutineScope,
+) : AudioRepository {
+
+ override val mode: StateFlow<Int> =
+ callbackFlow {
+ val listener =
+ AudioManager.OnModeChangedListener { newMode -> launch { send(newMode) } }
+ audioManager.addOnModeChangedListener(ConcurrentUtils.DIRECT_EXECUTOR, listener)
+ awaitClose { audioManager.removeOnModeChangedListener(listener) }
+ }
+ .flowOn(backgroundCoroutineContext)
+ .stateIn(coroutineScope, SharingStarted.WhileSubscribed(), audioManager.mode)
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/volume/domain/interactor/AudioModeInteractor.kt b/packages/SettingsLib/src/com/android/settingslib/volume/domain/interactor/AudioModeInteractor.kt
new file mode 100644
index 0000000..053c59b
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/volume/domain/interactor/AudioModeInteractor.kt
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.volume.domain.interactor
+
+import android.media.AudioManager
+import com.android.settingslib.volume.data.repository.AudioRepository
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.map
+
+class AudioModeInteractor(repository: AudioRepository) {
+
+ private val ongoingCallModes =
+ setOf(
+ AudioManager.MODE_RINGTONE,
+ AudioManager.MODE_IN_CALL,
+ AudioManager.MODE_IN_COMMUNICATION,
+ )
+
+ /** Returns if current [AudioManager.getMode] call is an ongoing call */
+ val isOngoingCall: Flow<Boolean> = repository.mode.map { it in ongoingCallModes }
+}
diff --git a/packages/SettingsLib/tests/integ/Android.bp b/packages/SettingsLib/tests/integ/Android.bp
index 644b72c..ce3a7ba 100644
--- a/packages/SettingsLib/tests/integ/Android.bp
+++ b/packages/SettingsLib/tests/integ/Android.bp
@@ -57,6 +57,7 @@
"SettingsLibSettingsSpinner",
"SettingsLibUsageProgressBarPreference",
"settingslib_media_flags_lib",
+ "kotlinx_coroutines_test",
],
dxflags: ["--multi-dex"],
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/volume/data/repository/FakeAudioRepository.kt b/packages/SettingsLib/tests/integ/src/com/android/settingslib/volume/data/repository/FakeAudioRepository.kt
new file mode 100644
index 0000000..686362f
--- /dev/null
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/volume/data/repository/FakeAudioRepository.kt
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.volume.data.repository
+
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.asStateFlow
+
+class FakeAudioRepository : AudioRepository {
+
+ private val mutableMode = MutableStateFlow(0)
+ override val mode: StateFlow<Int>
+ get() = mutableMode.asStateFlow()
+
+ fun setMode(newMode: Int) {
+ mutableMode.value = newMode
+ }
+}
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/volume/domain/interactor/AudioModeInteractorTest.kt b/packages/SettingsLib/tests/integ/src/com/android/settingslib/volume/domain/interactor/AudioModeInteractorTest.kt
new file mode 100644
index 0000000..3bc1edc
--- /dev/null
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/volume/domain/interactor/AudioModeInteractorTest.kt
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.volume.domain.interactor
+
+import android.media.AudioManager
+import androidx.test.filters.SmallTest
+import androidx.test.runner.AndroidJUnit4
+import com.android.settingslib.volume.data.repository.FakeAudioRepository
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@RunWith(AndroidJUnit4::class)
+@SmallTest
+class AudioModeInteractorTest {
+
+ private val testScope = TestScope()
+ private val fakeAudioRepository = FakeAudioRepository()
+
+ private val underTest = AudioModeInteractor(fakeAudioRepository)
+
+ @Test
+ fun ongoingCallModes_isOnGoingCall() {
+ testScope.runTest {
+ for (mode in ongoingCallModes) {
+ var isOngoingCall = false
+ underTest.isOngoingCall.onEach { isOngoingCall = it }.launchIn(backgroundScope)
+
+ fakeAudioRepository.setMode(mode)
+ runCurrent()
+
+ assertThat(isOngoingCall).isTrue()
+ }
+ }
+ }
+
+ @Test
+ fun notOngoingCallModes_isNotOnGoingCall() {
+ testScope.runTest {
+ var isOngoingCall = true
+ underTest.isOngoingCall.onEach { isOngoingCall = it }.launchIn(backgroundScope)
+
+ fakeAudioRepository.setMode(AudioManager.MODE_CURRENT)
+ runCurrent()
+
+ assertThat(isOngoingCall).isFalse()
+ }
+ }
+
+ private companion object {
+ private val ongoingCallModes =
+ setOf(
+ AudioManager.MODE_RINGTONE,
+ AudioManager.MODE_IN_CALL,
+ AudioManager.MODE_IN_COMMUNICATION,
+ )
+ }
+}
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index cdb4aea..95e0e1b 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -899,6 +899,9 @@
<!-- Permission required for Cts test - CtsNotificationTestCases -->
<uses-permission android:name="android.permission.RECEIVE_SENSITIVE_NOTIFICATIONS" />
+ <!-- Permission required for Cts test - CtsWindowManagerJetpackTestCases -->
+ <uses-permission android:name="android.permission.EMBED_ANY_APP_IN_UNTRUSTED_MODE" />
+
<!-- Permission required for BinaryTransparencyService shell API and host test -->
<uses-permission android:name="android.permission.GET_BACKGROUND_INSTALLED_PACKAGES" />
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index 80656e9..900a2f8 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -214,6 +214,8 @@
javacflags: [
"-Adagger.fastInit=enabled",
+ "-Adagger.explicitBindingConflictsWithInject=ERROR",
+ "-Adagger.strictMultibindingValidation=enabled",
"-Aroom.schemaLocation=frameworks/base/packages/SystemUI/schemas",
],
kotlincflags: ["-Xjvm-default=all"],
@@ -330,6 +332,7 @@
"androidx.core_core-animation-testing-nodeps",
"androidx.compose.ui_ui",
"flag-junit",
+ "ravenwood-junit",
"platform-test-annotations",
"notification_flags_lib",
],
@@ -386,7 +389,8 @@
android_app {
name: "SystemUIRobo-stub",
- use_resource_processor: true,
+ // SystemUiRavenTests references the .aapt.srcjar
+ use_resource_processor: false,
defaults: [
"platform_app_defaults",
"SystemUI_optimized_defaults",
@@ -458,6 +462,34 @@
],
}
+android_ravenwood_test {
+ name: "SystemUiRavenTests",
+ srcs: [
+ ":SystemUI-tests-utils",
+ ":SystemUI-tests-multivalent",
+ // TODO(b/294256649): pivot to using {.aapt.jar} and re-enable
+ // use_resource_processor: true when better supported by soong
+ ":SystemUIRobo-stub{.aapt.srcjar}",
+ ],
+ static_libs: [
+ "SystemUI-core",
+ "SystemUI-res",
+ "SystemUI-tests-base",
+ "androidx.test.uiautomator_uiautomator",
+ "androidx.core_core-animation-testing",
+ "androidx.test.ext.junit",
+ ],
+ libs: [
+ "android.test.runner",
+ "android.test.base",
+ "android.test.mock",
+ ],
+ auto_gen_config: true,
+ plugins: [
+ "dagger2-compiler",
+ ],
+}
+
// Opt-out config for optimizing the SystemUI target using R8.
// Disabled via `export SYSTEMUI_OPTIMIZE_JAVA=false`, or explicitly in Make via
// `SYSTEMUI_OPTIMIZE_JAVA := false`.
diff --git a/packages/SystemUI/aconfig/biometrics_framework.aconfig b/packages/SystemUI/aconfig/biometrics_framework.aconfig
index 5fd3b48..7cc0c83 100644
--- a/packages/SystemUI/aconfig/biometrics_framework.aconfig
+++ b/packages/SystemUI/aconfig/biometrics_framework.aconfig
@@ -7,4 +7,11 @@
namespace: "biometrics_framework"
description: "Adds talkback directional guidance when using UDFPS with biometric prompt"
bug: "310044658"
+}
+
+flag {
+ name: "constraint_bp"
+ namespace: "biometrics_framework"
+ description: "Refactors Biometric Prompt to use a ConstraintLayout"
+ bug: "288175072"
}
\ No newline at end of file
diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig
index a2530d5..375fe13 100644
--- a/packages/SystemUI/aconfig/systemui.aconfig
+++ b/packages/SystemUI/aconfig/systemui.aconfig
@@ -371,3 +371,10 @@
description: "Enables refactored logic for SysUI+WM unlock/occlusion code paths"
bug: "278086361"
}
+
+flag {
+ name: "enable_keyguard_compose"
+ namespace: "systemui"
+ description: "Enables the compose version of keyguard."
+ bug: "301968149"
+}
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
index 9c46ebdc..8194055 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
@@ -644,7 +644,7 @@
var candidate: RemoteAnimationTarget? = null
for (it in apps) {
if (it.mode == RemoteAnimationTarget.MODE_OPENING) {
- if (it.taskInfo != null && !it.hasAnimatingParent) {
+ if (!it.hasAnimatingParent) {
return it
}
if (candidate == null) {
diff --git a/packages/SystemUI/compose/core/src/com/android/compose/PlatformButtons.kt b/packages/SystemUI/compose/core/src/com/android/compose/PlatformButtons.kt
index bb2fbf7..a18b460 100644
--- a/packages/SystemUI/compose/core/src/com/android/compose/PlatformButtons.kt
+++ b/packages/SystemUI/compose/core/src/com/android/compose/PlatformButtons.kt
@@ -17,6 +17,7 @@
package com.android.compose
+import androidx.annotation.DrawableRes
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.RowScope
@@ -24,8 +25,13 @@
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.ButtonColors
import androidx.compose.material3.ButtonDefaults
+import androidx.compose.material3.Icon
+import androidx.compose.material3.IconButton
+import androidx.compose.material3.IconButtonColors
+import androidx.compose.material3.IconButtonDefaults
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
+import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import com.android.compose.theme.LocalAndroidColorScheme
@@ -89,6 +95,29 @@
)
}
+@Composable
+fun PlatformIconButton(
+ onClick: () -> Unit,
+ modifier: Modifier = Modifier,
+ enabled: Boolean = true,
+ colors: IconButtonColors = iconButtonColors(),
+ @DrawableRes iconResource: Int,
+ contentDescription: String?,
+) {
+ IconButton(
+ modifier = modifier,
+ onClick = onClick,
+ enabled = enabled,
+ colors = colors,
+ ) {
+ Icon(
+ painter = painterResource(id = iconResource),
+ contentDescription = contentDescription,
+ tint = colors.contentColor,
+ )
+ }
+}
+
private val DefaultPlatformButtonVerticalPadding = 6.dp
private val ButtonPaddings = PaddingValues(horizontal = 16.dp, vertical = 8.dp)
@@ -109,6 +138,13 @@
}
@Composable
+private fun iconButtonColors(): IconButtonColors {
+ return IconButtonDefaults.filledIconButtonColors(
+ contentColor = LocalAndroidColorScheme.current.onSurface,
+ )
+}
+
+@Composable
private fun outlineButtonBorder(): BorderStroke {
return BorderStroke(
width = 1.dp,
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PasswordBouncer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PasswordBouncer.kt
index 0960811..f9b91cf 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PasswordBouncer.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PasswordBouncer.kt
@@ -14,9 +14,10 @@
* limitations under the License.
*/
+@file:OptIn(ExperimentalComposeUiApi::class)
+
package com.android.systemui.bouncer.ui.composable
-import android.view.ViewTreeObserver
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material3.LocalTextStyle
@@ -25,25 +26,25 @@
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.State
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
-import androidx.compose.runtime.produceState
import androidx.compose.runtime.remember
+import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.drawBehind
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.focus.onFocusChanged
import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.input.key.Key
+import androidx.compose.ui.input.key.key
+import androidx.compose.ui.input.key.onInterceptKeyBeforeSoftKeyboard
import androidx.compose.ui.platform.LocalDensity
-import androidx.compose.ui.platform.LocalView
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.input.PasswordVisualTransformation
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
-import androidx.core.view.WindowInsetsCompat
import com.android.systemui.bouncer.ui.viewmodel.PasswordBouncerViewModel
/** UI for the input part of a password-requiring version of the bouncer. */
@@ -64,9 +65,6 @@
val isInputEnabled: Boolean by viewModel.isInputEnabled.collectAsState()
val animateFailure: Boolean by viewModel.animateFailure.collectAsState()
- val isImeVisible by isSoftwareKeyboardVisible()
- LaunchedEffect(isImeVisible) { viewModel.onImeVisibilityChanged(isImeVisible) }
-
DisposableEffect(Unit) {
viewModel.onShown()
onDispose { viewModel.onHidden() }
@@ -109,27 +107,14 @@
end = Offset(size.width, y = size.height - lineWidthPx),
strokeWidth = lineWidthPx,
)
+ }
+ .onInterceptKeyBeforeSoftKeyboard { keyEvent ->
+ if (keyEvent.key == Key.Back) {
+ viewModel.onImeDismissed()
+ true
+ } else {
+ false
+ }
},
)
}
-
-/** Returns a [State] with `true` when the IME/keyboard is visible and `false` when it's not. */
-@Composable
-fun isSoftwareKeyboardVisible(): State<Boolean> {
- val view = LocalView.current
- val viewTreeObserver = view.viewTreeObserver
-
- return produceState(
- initialValue = false,
- key1 = viewTreeObserver,
- ) {
- val listener =
- ViewTreeObserver.OnGlobalLayoutListener {
- value = view.rootWindowInsets?.isVisible(WindowInsetsCompat.Type.ime()) ?: false
- }
-
- viewTreeObserver.addOnGlobalLayoutListener(listener)
-
- awaitDispose { viewTreeObserver.removeOnGlobalLayoutListener(listener) }
- }
-}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt
index 4fdcf75..ff5a698 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt
@@ -64,14 +64,6 @@
transitions = sceneTransitions,
)
- // Don't show hub mode UI if communal is not available. Communal is only available if it has
- // been enabled via settings and either keyguard is showing, or, the device is currently
- // dreaming.
- val isCommunalAvailable by viewModel.isCommunalAvailable.collectAsState()
- if (!isCommunalAvailable) {
- return
- }
-
// This effect exposes the SceneTransitionLayout's observable transition state to the rest of
// the system, and unsets it when the view is disposed to avoid a memory leak.
DisposableEffect(viewModel, sceneTransitionLayoutState) {
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt
index 761e74e..576596f 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt
@@ -48,7 +48,6 @@
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Add
-import androidx.compose.material.icons.filled.Edit
import androidx.compose.material.icons.outlined.Delete
import androidx.compose.material.icons.outlined.Edit
import androidx.compose.material.icons.outlined.TouchApp
@@ -60,7 +59,6 @@
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.FilledIconButton
import androidx.compose.material3.Icon
-import androidx.compose.material3.IconButton
import androidx.compose.material3.IconButtonColors
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedButton
@@ -130,12 +128,11 @@
val gridState = rememberLazyGridState()
val contentListState = rememberContentListState(widgetConfigurator, communalContent, viewModel)
val reorderingWidgets by viewModel.reorderingWidgets.collectAsState()
- val selectedIndex = viewModel.selectedIndex.collectAsState()
+ val selectedKey = viewModel.selectedKey.collectAsState()
val removeButtonEnabled by remember {
- derivedStateOf { selectedIndex.value != null || reorderingWidgets }
+ derivedStateOf { selectedKey.value != null || reorderingWidgets }
}
- val (isButtonToEditWidgetsShowing, setIsButtonToEditWidgetsShowing) =
- remember { mutableStateOf(false) }
+ var isButtonToEditWidgetsShowing by remember { mutableStateOf(false) }
val contentPadding = gridContentPadding(viewModel.isEditMode, toolbarSize)
val contentOffset = beforeContentPadding(contentPadding).toOffset()
@@ -150,22 +147,30 @@
if (!viewModel.isEditMode) return@pointerInput
observeTapsWithoutConsuming { offset ->
val adjustedOffset = offset - contentOffset
- val index =
- gridState.layoutInfo.visibleItemsInfo
- .firstItemAtOffset(adjustedOffset)
- ?.index
- val newIndex =
- if (index?.let(contentListState::isItemEditable) == true) {
- index
- } else {
- null
- }
- viewModel.setSelectedIndex(newIndex)
+ val index = firstIndexAtOffset(gridState, adjustedOffset)
+ val key = index?.let { keyAtIndexIfEditable(contentListState.list, index) }
+ viewModel.setSelectedKey(key)
}
}
.thenIf(!viewModel.isEditMode) {
- Modifier.pointerInput(Unit) {
- detectLongPressGesture { offset -> setIsButtonToEditWidgetsShowing(true) }
+ Modifier.pointerInput(
+ gridState,
+ contentOffset,
+ communalContent,
+ gridCoordinates
+ ) {
+ detectLongPressGesture { offset ->
+ isButtonToEditWidgetsShowing = true
+
+ // Deduct both grid offset relative to its container and content offset.
+ val adjustedOffset =
+ gridCoordinates?.let {
+ offset - it.positionInWindow() - contentOffset
+ }
+ val index = adjustedOffset?.let { firstIndexAtOffset(gridState, it) }
+ val key = index?.let { keyAtIndexIfEditable(communalContent, index) }
+ viewModel.setSelectedKey(key)
+ }
}
},
) {
@@ -186,7 +191,7 @@
onOpenWidgetPicker = onOpenWidgetPicker,
gridState = gridState,
contentListState = contentListState,
- selectedIndex = selectedIndex,
+ selectedKey = selectedKey,
widgetConfigurator = widgetConfigurator,
)
@@ -198,18 +203,18 @@
onEditDone = onEditDone,
onOpenWidgetPicker = onOpenWidgetPicker,
onRemoveClicked = {
- selectedIndex.value?.let { index ->
- contentListState.onRemove(index)
+ val index =
+ selectedKey.value?.let { key ->
+ contentListState.list.indexOfFirst { it.key == key }
+ }
+ index?.let {
+ contentListState.onRemove(it)
contentListState.onSaveList()
- viewModel.setSelectedIndex(null)
+ viewModel.setSelectedKey(null)
}
},
removeEnabled = removeButtonEnabled
)
- } else {
- IconButton(onClick = viewModel::onOpenWidgetEditor) {
- Icon(Icons.Default.Edit, stringResource(R.string.button_to_open_widget_editor))
- }
}
if (isPopupOnDismissCtaShowing) {
@@ -219,10 +224,10 @@
if (isButtonToEditWidgetsShowing) {
ButtonToEditWidgets(
onClick = {
- setIsButtonToEditWidgetsShowing(false)
- viewModel.onOpenWidgetEditor()
+ isButtonToEditWidgetsShowing = false
+ viewModel.onOpenWidgetEditor(selectedKey.value)
},
- onHide = { setIsButtonToEditWidgetsShowing(false) },
+ onHide = { isButtonToEditWidgetsShowing = false },
)
}
@@ -244,7 +249,7 @@
communalContent: List<CommunalContentModel>,
viewModel: BaseCommunalViewModel,
contentPadding: PaddingValues,
- selectedIndex: State<Int?>,
+ selectedKey: State<String?>,
contentOffset: Offset,
gridState: LazyGridState,
contentListState: ContentListState,
@@ -253,7 +258,8 @@
onOpenWidgetPicker: (() -> Unit)? = null,
widgetConfigurator: WidgetConfigurator?,
) {
- var gridModifier = Modifier.align(Alignment.CenterStart)
+ var gridModifier =
+ Modifier.align(Alignment.CenterStart).onGloballyPositioned { setGridCoordinates(it) }
var list = communalContent
var dragDropState: GridDragDropState? = null
if (viewModel.isEditMode && viewModel is CommunalEditModeViewModel) {
@@ -266,10 +272,7 @@
updateDragPositionForRemove = updateDragPositionForRemove
)
gridModifier =
- gridModifier
- .fillMaxSize()
- .dragContainer(dragDropState, contentOffset, viewModel)
- .onGloballyPositioned { setGridCoordinates(it) }
+ gridModifier.fillMaxSize().dragContainer(dragDropState, contentOffset, viewModel)
// for widgets dropped from other activities
val dragAndDropTargetState =
rememberDragAndDropTargetState(
@@ -307,7 +310,8 @@
list[index].size.dp().value,
)
if (viewModel.isEditMode && dragDropState != null) {
- val selected by remember(index) { derivedStateOf { index == selectedIndex.value } }
+ val selected by
+ remember(index) { derivedStateOf { list[index].key == selectedKey.value } }
DraggableItem(
dragDropState = dragDropState,
selected = selected,
@@ -378,7 +382,7 @@
colors = filledButtonColors(),
contentPadding = Dimensions.ButtonPadding
) {
- Icon(Icons.Default.Add, stringResource(R.string.button_to_open_widget_editor))
+ Icon(Icons.Default.Add, stringResource(R.string.hub_mode_add_widget_button_text))
Spacer(spacerModifier)
Text(
text = stringResource(R.string.hub_mode_add_widget_button_text),
@@ -832,6 +836,13 @@
}
}
+private fun firstIndexAtOffset(gridState: LazyGridState, offset: Offset): Int? =
+ gridState.layoutInfo.visibleItemsInfo.firstItemAtOffset(offset)?.index
+
+/** Returns the key of item if it's editable at the given index. Only widget is editable. */
+private fun keyAtIndexIfEditable(list: List<CommunalContentModel>, index: Int): String? =
+ if (index in list.indices && list[index].isWidget()) list[index].key else null
+
data class ContentPaddingInPx(val start: Float, val top: Float) {
fun toOffset(): Offset = Offset(start, top)
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeHeader.kt b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeHeader.kt
index e2beaee..b11edf7 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeHeader.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeHeader.kt
@@ -58,6 +58,8 @@
import com.android.systemui.common.ui.compose.windowinsets.CutoutLocation
import com.android.systemui.common.ui.compose.windowinsets.LocalDisplayCutout
import com.android.systemui.res.R
+import com.android.systemui.scene.ui.composable.QuickSettings
+import com.android.systemui.scene.ui.composable.Shade as ShadeKey
import com.android.systemui.shade.ui.viewmodel.ShadeHeaderViewModel
import com.android.systemui.statusbar.phone.StatusBarIconController
import com.android.systemui.statusbar.phone.StatusBarIconController.TintedIconManager
@@ -348,7 +350,7 @@
}
@Composable
-private fun StatusIcons(
+private fun SceneScope.StatusIcons(
viewModel: ShadeHeaderViewModel,
createTintedIconManager: (ViewGroup, StatusBarLocation) -> TintedIconManager,
statusBarIconController: StatusBarIconController,
@@ -358,7 +360,6 @@
val carrierIconSlots =
listOf(stringResource(id = com.android.internal.R.string.status_bar_mobile))
val isSingleCarrier by viewModel.isSingleCarrier.collectAsState()
- val isTransitioning by viewModel.isTransitioning.collectAsState()
AndroidView(
factory = { context ->
@@ -373,7 +374,9 @@
iconContainer
},
update = { iconContainer ->
- iconContainer.setQsExpansionTransitioning(isTransitioning)
+ iconContainer.setQsExpansionTransitioning(
+ layoutState.isTransitioningBetween(ShadeKey, QuickSettings)
+ )
if (isSingleCarrier || !useExpandedFormat) {
iconContainer.removeIgnoredSlots(carrierIconSlots)
} else {
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MultiPointerDraggable.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MultiPointerDraggable.kt
index 8552aaf..5f615fd 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MultiPointerDraggable.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MultiPointerDraggable.kt
@@ -40,12 +40,15 @@
import androidx.compose.ui.node.CompositionLocalConsumerModifierNode
import androidx.compose.ui.node.DelegatingNode
import androidx.compose.ui.node.ModifierNodeElement
+import androidx.compose.ui.node.ObserverModifierNode
import androidx.compose.ui.node.PointerInputModifierNode
import androidx.compose.ui.node.currentValueOf
+import androidx.compose.ui.node.observeReads
import androidx.compose.ui.platform.LocalViewConfiguration
import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.unit.Velocity
import androidx.compose.ui.util.fastForEach
+import kotlin.math.sign
/**
* Make an element draggable in the given [orientation].
@@ -65,7 +68,7 @@
internal fun Modifier.multiPointerDraggable(
orientation: Orientation,
enabled: () -> Boolean,
- startDragImmediately: () -> Boolean,
+ startDragImmediately: (startedPosition: Offset) -> Boolean,
onDragStarted: (startedPosition: Offset, overSlop: Float, pointersDown: Int) -> Unit,
onDragDelta: (delta: Float) -> Unit,
onDragStopped: (velocity: Float) -> Unit,
@@ -84,7 +87,7 @@
private data class MultiPointerDraggableElement(
private val orientation: Orientation,
private val enabled: () -> Boolean,
- private val startDragImmediately: () -> Boolean,
+ private val startDragImmediately: (startedPosition: Offset) -> Boolean,
private val onDragStarted:
(startedPosition: Offset, overSlop: Float, pointersDown: Int) -> Unit,
private val onDragDelta: (Float) -> Unit,
@@ -113,14 +116,19 @@
internal class MultiPointerDraggableNode(
orientation: Orientation,
enabled: () -> Boolean,
- var startDragImmediately: () -> Boolean,
+ var startDragImmediately: (startedPosition: Offset) -> Boolean,
var onDragStarted: (startedPosition: Offset, overSlop: Float, pointersDown: Int) -> Unit,
var onDragDelta: (Float) -> Unit,
var onDragStopped: (velocity: Float) -> Unit,
-) : PointerInputModifierNode, DelegatingNode(), CompositionLocalConsumerModifierNode {
+) :
+ PointerInputModifierNode,
+ DelegatingNode(),
+ CompositionLocalConsumerModifierNode,
+ ObserverModifierNode {
private val pointerInputHandler: suspend PointerInputScope.() -> Unit = { pointerInput() }
private val delegate = delegate(SuspendingPointerInputModifierNode(pointerInputHandler))
private val velocityTracker = VelocityTracker()
+ private var previousEnabled: Boolean = false
var enabled: () -> Boolean = enabled
set(value) {
@@ -140,6 +148,21 @@
}
}
+ override fun onAttach() {
+ previousEnabled = enabled()
+ onObservedReadsChanged()
+ }
+
+ override fun onObservedReadsChanged() {
+ observeReads {
+ val newEnabled = enabled()
+ if (newEnabled != previousEnabled) {
+ delegate.resetPointerInputHandler()
+ }
+ previousEnabled = newEnabled
+ }
+ }
+
override fun onCancelPointerInput() = delegate.onCancelPointerInput()
override fun onPointerEvent(
@@ -201,7 +224,7 @@
*/
private suspend fun PointerInputScope.detectDragGestures(
orientation: Orientation,
- startDragImmediately: () -> Boolean,
+ startDragImmediately: (startedPosition: Offset) -> Boolean,
onDragStart: (startedPosition: Offset, overSlop: Float, pointersDown: Int) -> Unit,
onDragEnd: () -> Unit,
onDragCancel: () -> Unit,
@@ -211,7 +234,7 @@
val initialDown = awaitFirstDown(requireUnconsumed = false, pass = PointerEventPass.Initial)
var overSlop = 0f
val drag =
- if (startDragImmediately()) {
+ if (startDragImmediately(initialDown.position)) {
initialDown.consume()
initialDown
} else {
@@ -223,12 +246,31 @@
// TODO(b/291055080): Replace by await[Orientation]PointerSlopOrCancellation once
// it is public.
- when (orientation) {
- Orientation.Horizontal ->
- awaitHorizontalTouchSlopOrCancellation(down.id, onSlopReached)
- Orientation.Vertical ->
- awaitVerticalTouchSlopOrCancellation(down.id, onSlopReached)
+ val drag =
+ when (orientation) {
+ Orientation.Horizontal ->
+ awaitHorizontalTouchSlopOrCancellation(down.id, onSlopReached)
+ Orientation.Vertical ->
+ awaitVerticalTouchSlopOrCancellation(down.id, onSlopReached)
+ }
+
+ // Make sure that overSlop is not 0f. This can happen when the user drags by exactly
+ // the touch slop. However, the overSlop we pass to onDragStarted() is used to
+ // compute the direction we are dragging in, so overSlop should never be 0f unless
+ // we intercept an ongoing swipe transition (i.e. startDragImmediately() returned
+ // true).
+ if (drag != null && overSlop == 0f) {
+ val deltaOffset = drag.position - initialDown.position
+ val delta =
+ when (orientation) {
+ Orientation.Horizontal -> deltaOffset.y
+ Orientation.Vertical -> deltaOffset.y
+ }
+ check(delta != 0f)
+ overSlop = delta.sign
}
+
+ drag
}
if (drag != null) {
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneGestureHandler.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneGestureHandler.kt
index aed04f6..58c3be24 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneGestureHandler.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneGestureHandler.kt
@@ -20,8 +20,7 @@
import android.util.Log
import androidx.compose.animation.core.Animatable
-import androidx.compose.animation.core.Spring
-import androidx.compose.animation.core.spring
+import androidx.compose.animation.core.SpringSpec
import androidx.compose.foundation.gestures.Orientation
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableFloatStateOf
@@ -54,7 +53,20 @@
}
private fun updateTransition(newTransition: SwipeTransition, force: Boolean = false) {
- if (isDrivingTransition || force) layoutState.startTransition(newTransition)
+ if (isDrivingTransition || force) {
+ layoutState.startTransition(newTransition)
+
+ // Initialize SwipeTransition.swipeSpec. Note that this must be called right after
+ // layoutState.startTransition() is called, because it computes the
+ // layoutState.transformationSpec().
+ newTransition.swipeSpec =
+ layoutState.transformationSpec.swipeSpec ?: layoutState.transitions.defaultSwipeSpec
+ } else {
+ // We were not driving the transition and we don't force the update, so the spec won't
+ // be used and it doesn't matter which one we set here.
+ newTransition.swipeSpec = SceneTransitions.DefaultSwipeSpec
+ }
+
swipeTransition = newTransition
}
@@ -84,8 +96,35 @@
private var upOrLeftResult: UserActionResult? = null
private var downOrRightResult: UserActionResult? = null
+ /**
+ * Whether we should immediately intercept a gesture.
+ *
+ * Note: if this returns true, then [onDragStarted] will be called with overSlop equal to 0f,
+ * indicating that the transition should be intercepted.
+ */
+ internal fun shouldImmediatelyIntercept(startedPosition: Offset?): Boolean {
+ // We don't intercept the touch if we are not currently driving the transition.
+ if (!isDrivingTransition) {
+ return false
+ }
+
+ // Only intercept the current transition if one of the 2 swipes results is also a transition
+ // between the same pair of scenes.
+ val fromScene = swipeTransition._currentScene
+ val swipes = computeSwipes(fromScene, startedPosition, pointersDown = 1)
+ val (upOrLeft, downOrRight) = computeSwipesResults(fromScene, swipes)
+ return (upOrLeft != null &&
+ swipeTransition.isTransitioningBetween(fromScene.key, upOrLeft.toScene)) ||
+ (downOrRight != null &&
+ swipeTransition.isTransitioningBetween(fromScene.key, downOrRight.toScene))
+ }
+
internal fun onDragStarted(pointersDown: Int, startedPosition: Offset?, overSlop: Float) {
- if (isDrivingTransition) {
+ if (overSlop == 0f) {
+ check(isDrivingTransition) {
+ "onDragStarted() called while isDrivingTransition=false overSlop=0f"
+ }
+
// This [transition] was already driving the animation: simply take over it.
// Stop animating and start from where the current offset.
swipeTransition.cancelOffsetAnimation()
@@ -93,9 +132,6 @@
return
}
- check(overSlop != 0f) {
- "onDragStarted() called while isDrivingTransition=false overSlop=0f"
- }
val transitionState = layoutState.transitionState
if (transitionState is TransitionState.Transition) {
// TODO(b/290184746): Better handle interruptions here if state != idle.
@@ -211,7 +247,7 @@
private fun updateSwipesResults(fromScene: Scene) {
val (upOrLeftResult, downOrRightResult) =
- swipesResults(
+ computeSwipesResults(
fromScene,
this.swipes ?: error("updateSwipes() should be called before updateSwipesResults()")
)
@@ -220,7 +256,7 @@
this.downOrRightResult = downOrRightResult
}
- private fun swipesResults(
+ private fun computeSwipesResults(
fromScene: Scene,
swipes: Swipes
): Pair<UserActionResult?, UserActionResult?> {
@@ -346,6 +382,11 @@
return
}
+ // Important: Make sure that all the code here references the current transition when
+ // [onDragStopped] is called, otherwise the callbacks (like onAnimationCompleted()) might
+ // incorrectly finish a new transition that replaced this one.
+ val swipeTransition = this.swipeTransition
+
fun animateTo(targetScene: Scene, targetOffset: Float) {
// If the effective current scene changed, it should be reflected right now in the
// current scene state, even before the settle animation is ongoing. That way all the
@@ -462,7 +503,7 @@
* The signed distance between [fromScene] and [toScene]. It is negative if [fromScene] is
* above or to the left of [toScene].
*/
- val distance: Float
+ val distance: Float,
) : TransitionState.Transition(_fromScene.key, _toScene.key) {
var _currentScene by mutableStateOf(_fromScene)
override val currentScene: SceneKey
@@ -495,6 +536,9 @@
/** Job to check that there is at most one offset animation in progress. */
private var offsetAnimationJob: Job? = null
+ /** The spec to use when animating this transition to either [fromScene] or [toScene]. */
+ lateinit var swipeSpec: SpringSpec<Float>
+
/** Ends any previous [offsetAnimationJob] and runs the new [job]. */
private fun startOffsetAnimation(job: () -> Job) {
cancelOffsetAnimation()
@@ -516,13 +560,6 @@
}
}
- // TODO(b/290184746): Make this spring spec configurable.
- private val animationSpec =
- spring(
- stiffness = Spring.StiffnessMediumLow,
- visibilityThreshold = OffsetVisibilityThreshold
- )
-
fun animateOffset(
// TODO(b/317063114) The CoroutineScope should be removed.
coroutineScope: CoroutineScope,
@@ -546,7 +583,7 @@
offsetAnimatable.animateTo(
targetValue = targetOffset,
- animationSpec = animationSpec,
+ animationSpec = swipeSpec,
initialVelocity = initialVelocity,
)
@@ -651,6 +688,7 @@
}
val source = this
+ var isIntercepting = false
return PriorityNestedScrollConnection(
orientation = orientation,
@@ -658,7 +696,9 @@
canChangeScene = offsetBeforeStart == 0f
val canInterceptSwipeTransition =
- canChangeScene && gestureHandler.isDrivingTransition && offsetAvailable != 0f
+ canChangeScene &&
+ offsetAvailable != 0f &&
+ gestureHandler.shouldImmediatelyIntercept(startedPosition = null)
if (!canInterceptSwipeTransition) return@PriorityNestedScrollConnection false
val swipeTransition = gestureHandler.swipeTransition
@@ -676,7 +716,12 @@
}
// Start only if we cannot consume this event
- !shouldSnapToIdle
+ val canStart = !shouldSnapToIdle
+ if (canStart) {
+ isIntercepting = true
+ }
+
+ canStart
},
canStartPostScroll = { offsetAvailable, offsetBeforeStart ->
val behavior: NestedScrollBehavior =
@@ -688,24 +733,31 @@
val isZeroOffset = offsetBeforeStart == 0f
- when (behavior) {
- NestedScrollBehavior.DuringTransitionBetweenScenes -> {
- canChangeScene = false // unused: added for consistency
- false
+ val canStart =
+ when (behavior) {
+ NestedScrollBehavior.DuringTransitionBetweenScenes -> {
+ canChangeScene = false // unused: added for consistency
+ false
+ }
+ NestedScrollBehavior.EdgeNoPreview -> {
+ canChangeScene = isZeroOffset
+ isZeroOffset && hasNextScene(offsetAvailable)
+ }
+ NestedScrollBehavior.EdgeWithPreview -> {
+ canChangeScene = isZeroOffset
+ hasNextScene(offsetAvailable)
+ }
+ NestedScrollBehavior.EdgeAlways -> {
+ canChangeScene = true
+ hasNextScene(offsetAvailable)
+ }
}
- NestedScrollBehavior.EdgeNoPreview -> {
- canChangeScene = isZeroOffset
- isZeroOffset && hasNextScene(offsetAvailable)
- }
- NestedScrollBehavior.EdgeWithPreview -> {
- canChangeScene = isZeroOffset
- hasNextScene(offsetAvailable)
- }
- NestedScrollBehavior.EdgeAlways -> {
- canChangeScene = true
- hasNextScene(offsetAvailable)
- }
+
+ if (canStart) {
+ isIntercepting = false
}
+
+ canStart
},
canStartPostFling = { velocityAvailable ->
val behavior: NestedScrollBehavior =
@@ -717,7 +769,13 @@
// We could start an overscroll animation
canChangeScene = false
- behavior.canStartOnPostFling && hasNextScene(velocityAvailable)
+
+ val canStart = behavior.canStartOnPostFling && hasNextScene(velocityAvailable)
+ if (canStart) {
+ isIntercepting = false
+ }
+
+ canStart
},
canContinueScroll = { true },
canScrollOnFling = false,
@@ -726,7 +784,7 @@
gestureHandler.onDragStarted(
pointersDown = 1,
startedPosition = null,
- overSlop = offsetAvailable,
+ overSlop = if (isIntercepting) 0f else offsetAvailable,
)
},
onScroll = { offsetAvailable ->
@@ -761,4 +819,6 @@
* The number of pixels below which there won't be a visible difference in the transition and from
* which the animation can stop.
*/
-private const val OffsetVisibilityThreshold = 0.5f
+// TODO(b/290184746): Have a better default visibility threshold which takes the swipe distance into
+// account instead.
+internal const val OffsetVisibilityThreshold = 0.5f
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitions.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitions.kt
index 3a55567..ac423b7 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitions.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitions.kt
@@ -17,7 +17,10 @@
package com.android.compose.animation.scene
import androidx.compose.animation.core.AnimationSpec
+import androidx.compose.animation.core.Spring
+import androidx.compose.animation.core.SpringSpec
import androidx.compose.animation.core.snap
+import androidx.compose.animation.core.spring
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.util.fastForEach
@@ -36,6 +39,7 @@
/** The transitions configuration of a [SceneTransitionLayout]. */
class SceneTransitions
internal constructor(
+ internal val defaultSwipeSpec: SpringSpec<Float>,
internal val transitionSpecs: List<TransitionSpecImpl>,
) {
private val cache = mutableMapOf<SceneKey, MutableMap<SceneKey, TransitionSpecImpl>>()
@@ -91,7 +95,13 @@
TransitionSpecImpl(from, to, TransformationSpec.EmptyProvider)
companion object {
- val Empty = SceneTransitions(transitionSpecs = emptyList())
+ internal val DefaultSwipeSpec =
+ spring(
+ stiffness = Spring.StiffnessMediumLow,
+ visibilityThreshold = OffsetVisibilityThreshold,
+ )
+
+ val Empty = SceneTransitions(DefaultSwipeSpec, transitionSpecs = emptyList())
}
}
@@ -125,15 +135,30 @@
}
interface TransformationSpec {
- /** The [AnimationSpec] used to animate the associated transition progress. */
+ /**
+ * The [AnimationSpec] used to animate the associated transition progress from `0` to `1` when
+ * the transition is triggered (i.e. it is not gesture-based).
+ */
val progressSpec: AnimationSpec<Float>
+ /**
+ * The [SpringSpec] used to animate the associated transition progress when the transition was
+ * started by a swipe and is now animating back to a scene because the user lifted their finger.
+ *
+ * If `null`, then the [SceneTransitions.defaultSwipeSpec] will be used.
+ */
+ val swipeSpec: SpringSpec<Float>?
+
/** The list of [Transformation] applied to elements during this transition. */
val transformations: List<Transformation>
companion object {
internal val Empty =
- TransformationSpecImpl(progressSpec = snap(), transformations = emptyList())
+ TransformationSpecImpl(
+ progressSpec = snap(),
+ swipeSpec = null,
+ transformations = emptyList(),
+ )
internal val EmptyProvider = { Empty }
}
}
@@ -151,6 +176,7 @@
val reverse = transformationSpec.invoke()
TransformationSpecImpl(
progressSpec = reverse.progressSpec,
+ swipeSpec = reverse.swipeSpec,
transformations = reverse.transformations.map { it.reversed() }
)
}
@@ -166,6 +192,7 @@
*/
internal class TransformationSpecImpl(
override val progressSpec: AnimationSpec<Float>,
+ override val swipeSpec: SpringSpec<Float>?,
override val transformations: List<Transformation>,
) : TransformationSpec {
private val cache = mutableMapOf<ElementKey, MutableMap<SceneKey, ElementTransformations>>()
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeToScene.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeToScene.kt
index b9c4ac0..61f4978 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeToScene.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeToScene.kt
@@ -19,6 +19,7 @@
import androidx.compose.foundation.gestures.Orientation
import androidx.compose.runtime.Stable
import androidx.compose.ui.Modifier
+import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.input.pointer.PointerEvent
import androidx.compose.ui.input.pointer.PointerEventPass
import androidx.compose.ui.node.DelegatingNode
@@ -94,13 +95,10 @@
return userActions.keys.any { it is Swipe && it.direction.orientation == orientation }
}
- private fun startDragImmediately(): Boolean {
- // Immediately start the drag if this our transition is currently animating to a scene
- // (i.e. the user released their input pointer after swiping in this orientation) and the
- // user can't swipe in the other direction.
- return gestureHandler.isDrivingTransition &&
- gestureHandler.swipeTransition.isAnimatingOffset &&
- !canOppositeSwipe()
+ private fun startDragImmediately(startedPosition: Offset): Boolean {
+ // Immediately start the drag if the user can't swipe in the other direction and the gesture
+ // handler can intercept it.
+ return !canOppositeSwipe() && gestureHandler.shouldImmediatelyIntercept(startedPosition)
}
private fun canOppositeSwipe(): Boolean {
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDsl.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDsl.kt
index a764a527..04e0937 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDsl.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDsl.kt
@@ -17,6 +17,7 @@
package com.android.compose.animation.scene
import androidx.compose.animation.core.AnimationSpec
+import androidx.compose.animation.core.SpringSpec
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
@@ -31,6 +32,12 @@
@TransitionDsl
interface SceneTransitionsBuilder {
/**
+ * The default [AnimationSpec] used when after the user lifts their finger after starting a
+ * swipe to transition, to animate back into one of the 2 scenes we are transitioning to.
+ */
+ var defaultSwipeSpec: SpringSpec<Float>
+
+ /**
* Define the default animation to be played when transitioning [to] the specified scene, from
* any scene. For the animation specification to apply only when transitioning between two
* specific scenes, use [from] instead.
@@ -64,12 +71,20 @@
@TransitionDsl
interface TransitionBuilder : PropertyTransformationBuilder {
/**
- * The [AnimationSpec] used to animate the progress of this transition from `0` to `1` when
- * performing programmatic (not input pointer tracking) animations.
+ * The [AnimationSpec] used to animate the associated transition progress from `0` to `1` when
+ * the transition is triggered (i.e. it is not gesture-based).
*/
var spec: AnimationSpec<Float>
/**
+ * The [SpringSpec] used to animate the associated transition progress when the transition was
+ * started by a swipe and is now animating back to a scene because the user lifted their finger.
+ *
+ * If `null`, then the [SceneTransitionsBuilder.defaultSwipeSpec] will be used.
+ */
+ var swipeSpec: SpringSpec<Float>?
+
+ /**
* Define a progress-based range for the transformations inside [builder].
*
* For instance, the following will fade `Foo` during the first half of the transition then it
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDslImpl.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDslImpl.kt
index b96f9be..df186a1 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDslImpl.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDslImpl.kt
@@ -19,6 +19,7 @@
import androidx.compose.animation.core.AnimationSpec
import androidx.compose.animation.core.DurationBasedAnimationSpec
import androidx.compose.animation.core.Spring
+import androidx.compose.animation.core.SpringSpec
import androidx.compose.animation.core.VectorConverter
import androidx.compose.animation.core.spring
import androidx.compose.ui.geometry.Offset
@@ -40,10 +41,12 @@
builder: SceneTransitionsBuilder.() -> Unit,
): SceneTransitions {
val impl = SceneTransitionsBuilderImpl().apply(builder)
- return SceneTransitions(impl.transitionSpecs)
+ return SceneTransitions(impl.defaultSwipeSpec, impl.transitionSpecs)
}
private class SceneTransitionsBuilderImpl : SceneTransitionsBuilder {
+ override var defaultSwipeSpec: SpringSpec<Float> = SceneTransitions.DefaultSwipeSpec
+
val transitionSpecs = mutableListOf<TransitionSpecImpl>()
override fun to(to: SceneKey, builder: TransitionBuilder.() -> Unit): TransitionSpec {
@@ -67,6 +70,7 @@
val impl = TransitionBuilderImpl().apply(builder)
return TransformationSpecImpl(
progressSpec = impl.spec,
+ swipeSpec = impl.swipeSpec,
transformations = impl.transformations,
)
}
@@ -80,6 +84,7 @@
internal class TransitionBuilderImpl : TransitionBuilder {
val transformations = mutableListOf<Transformation>()
override var spec: AnimationSpec<Float> = spring(stiffness = Spring.StiffnessLow)
+ override var swipeSpec: SpringSpec<Float>? = null
private var range: TransformationRange? = null
private var reversed = false
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneGestureHandlerTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneGestureHandlerTest.kt
index 88363ad..e8cc0ec 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneGestureHandlerTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneGestureHandlerTest.kt
@@ -21,7 +21,6 @@
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
import androidx.compose.ui.input.nestedscroll.NestedScrollSource
-import androidx.compose.ui.test.ExperimentalTestApi
import androidx.compose.ui.unit.Density
import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.unit.Velocity
@@ -118,9 +117,6 @@
fun up(fractionOfScreen: Float) =
if (fractionOfScreen < 0f) error("use down()") else -down(fractionOfScreen)
- // Float tolerance for comparisons
- val tolerance = 0.00001f
-
// Offset y: 10% of the screen
val offsetY10 = Offset(x = 0f, y = down(0.1f))
@@ -150,31 +146,42 @@
fromScene: SceneKey? = null,
toScene: SceneKey? = null,
progress: Float? = null,
+ isUserInputOngoing: Boolean? = null
) {
+ val transition = transitionState
assertWithMessage("transitionState must be Transition")
- .that(transitionState is Transition)
+ .that(transition is Transition)
.isTrue()
+ transition as Transition
+
if (currentScene != null)
assertWithMessage("currentScene does not match")
- .that(transitionState.currentScene)
+ .that(transition.currentScene)
.isEqualTo(currentScene)
+
if (fromScene != null)
assertWithMessage("fromScene does not match")
- .that((transitionState as? Transition)?.fromScene)
+ .that(transition.fromScene)
.isEqualTo(fromScene)
+
if (toScene != null)
assertWithMessage("toScene does not match")
- .that((transitionState as? Transition)?.toScene)
+ .that(transition.toScene)
.isEqualTo(toScene)
+
if (progress != null)
assertWithMessage("progress does not match")
- .that((transitionState as? Transition)?.progress)
- .isWithin(tolerance)
+ .that(transition.progress)
+ .isWithin(0f) // returns true when comparing 0.0f with -0.0f
.of(progress)
+
+ if (isUserInputOngoing != null)
+ assertWithMessage("isUserInputOngoing does not match")
+ .that(transition.isUserInputOngoing)
+ .isEqualTo(isUserInputOngoing)
}
}
- @OptIn(ExperimentalTestApi::class)
private fun runGestureTest(block: suspend TestGestureScope.() -> Unit) {
runMonotonicClockTest { TestGestureScope(coroutineScope = this).block() }
}
@@ -248,7 +255,7 @@
@Test
fun onDragReversedDirection_changeToScene() = runGestureTest {
// Drag A -> B with progress 0.6
- draggable.onDragStarted(overSlop = up(0.6f))
+ draggable.onDragStarted(overSlop = -60f)
assertTransition(
currentScene = SceneA,
fromScene = SceneA,
@@ -257,7 +264,7 @@
)
// Reverse direction such that A -> C now with 0.4
- draggable.onDelta(down(1f))
+ draggable.onDelta(100f)
assertTransition(
currentScene = SceneA,
fromScene = SceneA,
@@ -287,7 +294,7 @@
navigateToSceneC()
// We are on SceneC which has no action in Down direction
- draggable.onDragStarted(down(0.1f))
+ draggable.onDragStarted(10f)
assertTransition(
currentScene = SceneC,
fromScene = SceneC,
@@ -296,7 +303,7 @@
)
// Reverse drag direction, it will consume the previous drag
- draggable.onDelta(up(0.1f))
+ draggable.onDelta(-10f)
assertTransition(
currentScene = SceneC,
fromScene = SceneC,
@@ -305,7 +312,7 @@
)
// Continue reverse drag direction, it should record progress to Scene B
- draggable.onDelta(up(0.1f))
+ draggable.onDelta(-10f)
assertTransition(
currentScene = SceneC,
fromScene = SceneC,
@@ -557,53 +564,53 @@
) {
val nestedScroll = nestedScrollConnection(nestedScrollBehavior = EdgeWithPreview)
// start scene transition
- nestedScroll.scroll(available = Offset(0f, SCREEN_SIZE * firstScroll))
+ nestedScroll.scroll(available = Offset(0f, firstScroll))
// stop scene transition (start the "stop animation")
nestedScroll.onPreFling(available = Velocity.Zero)
// a pre scroll event, that could be intercepted by SceneGestureHandler
- nestedScroll.onPreScroll(Offset(0f, SCREEN_SIZE * secondScroll), NestedScrollSource.Drag)
+ nestedScroll.onPreScroll(Offset(0f, secondScroll), NestedScrollSource.Drag)
}
@Test
fun scrollAndFling_scrollLessThanInterceptable_goToIdleOnCurrentScene() = runGestureTest {
- val first = transitionInterceptionThreshold - tolerance
- val second = 0.01f
+ val firstScroll = (transitionInterceptionThreshold - 0.0001f) * SCREEN_SIZE
+ val secondScroll = 1f
- preScrollAfterSceneTransition(firstScroll = first, secondScroll = second)
+ preScrollAfterSceneTransition(firstScroll = firstScroll, secondScroll = secondScroll)
assertIdle(SceneA)
}
@Test
fun scrollAndFling_scrollMinInterceptable_interceptPreScrollEvents() = runGestureTest {
- val first = transitionInterceptionThreshold + tolerance
- val second = 0.01f
+ val firstScroll = (transitionInterceptionThreshold + 0.0001f) * SCREEN_SIZE
+ val secondScroll = 1f
- preScrollAfterSceneTransition(firstScroll = first, secondScroll = second)
+ preScrollAfterSceneTransition(firstScroll = firstScroll, secondScroll = secondScroll)
- assertTransition(progress = first + second)
+ assertTransition(progress = (firstScroll + secondScroll) / SCREEN_SIZE)
}
@Test
fun scrollAndFling_scrollMaxInterceptable_interceptPreScrollEvents() = runGestureTest {
- val first = 1f - transitionInterceptionThreshold - tolerance
- val second = 0.01f
+ val firstScroll = -(1f - transitionInterceptionThreshold - 0.0001f) * SCREEN_SIZE
+ val secondScroll = -1f
- preScrollAfterSceneTransition(firstScroll = first, secondScroll = second)
+ preScrollAfterSceneTransition(firstScroll = firstScroll, secondScroll = secondScroll)
- assertTransition(progress = first + second)
+ assertTransition(progress = -(firstScroll + secondScroll) / SCREEN_SIZE)
}
@Test
fun scrollAndFling_scrollMoreThanInterceptable_goToIdleOnNextScene() = runGestureTest {
- val first = 1f - transitionInterceptionThreshold + tolerance
- val second = 0.01f
+ val firstScroll = -(1f - transitionInterceptionThreshold + 0.0001f) * SCREEN_SIZE
+ val secondScroll = -0.01f
- preScrollAfterSceneTransition(firstScroll = first, secondScroll = second)
+ preScrollAfterSceneTransition(firstScroll = firstScroll, secondScroll = secondScroll)
- assertIdle(SceneC)
+ assertIdle(SceneB)
}
@Test
@@ -745,29 +752,75 @@
@Test
fun startNestedScrollWhileDragging() = runGestureTest {
val nestedScroll = nestedScrollConnection(nestedScrollBehavior = EdgeAlways)
- draggable.onDragStarted(overSlop = down(0.1f))
+
+ // Start a drag and then stop it, given that
+ draggable.onDragStarted(overSlop = up(0.1f))
+
assertTransition(currentScene = SceneA)
assertThat(progress).isEqualTo(0.1f)
// now we can intercept the scroll events
- nestedScroll.scroll(available = offsetY10)
+ nestedScroll.scroll(available = -offsetY10)
assertThat(progress).isEqualTo(0.2f)
// this should be ignored, we are scrolling now!
- draggable.onDragStopped(velocityThreshold)
+ draggable.onDragStopped(-velocityThreshold)
assertTransition(currentScene = SceneA)
- nestedScroll.scroll(available = offsetY10)
+ nestedScroll.scroll(available = -offsetY10)
assertThat(progress).isEqualTo(0.3f)
- nestedScroll.scroll(available = offsetY10)
+ nestedScroll.scroll(available = -offsetY10)
assertThat(progress).isEqualTo(0.4f)
- nestedScroll.onPreFling(available = Velocity(0f, velocityThreshold))
- assertTransition(currentScene = SceneC)
+ nestedScroll.onPreFling(available = Velocity(0f, -velocityThreshold))
+ assertTransition(currentScene = SceneB)
// wait for the stop animation
advanceUntilIdle()
- assertIdle(currentScene = SceneC)
+ assertIdle(currentScene = SceneB)
+ }
+
+ @Test
+ fun interceptTransition() = runGestureTest {
+ // Start at scene C.
+ navigateToSceneC()
+
+ // Swipe up from the middle to transition to scene B.
+ val middle = Offset(SCREEN_SIZE / 2f, SCREEN_SIZE / 2f)
+ draggable.onDragStarted(startedPosition = middle, overSlop = up(0.1f))
+ assertTransition(
+ currentScene = SceneC,
+ fromScene = SceneC,
+ toScene = SceneB,
+ isUserInputOngoing = true,
+ )
+
+ val firstTransition = transitionState
+
+ // During the current gesture, start a new gesture, still in the middle of the screen. We
+ // should intercept it. Because it is intercepted, the overSlop passed to onDragStarted()
+ // should be 0f.
+ assertThat(sceneGestureHandler.shouldImmediatelyIntercept(middle)).isTrue()
+ draggable.onDragStarted(startedPosition = middle, overSlop = 0f)
+
+ // We should have intercepted the transition, so the transition should be the same object.
+ assertTransition(currentScene = SceneC, fromScene = SceneC, toScene = SceneB)
+ assertThat(transitionState).isSameInstanceAs(firstTransition)
+
+ // Start a new gesture from the bottom of the screen. Because swiping up from the bottom of
+ // C leads to scene A (and not B), the previous transitions is *not* intercepted and we
+ // instead animate from C to A.
+ val bottom = Offset(SCREEN_SIZE / 2, SCREEN_SIZE)
+ assertThat(sceneGestureHandler.shouldImmediatelyIntercept(bottom)).isFalse()
+ draggable.onDragStarted(startedPosition = bottom, overSlop = up(0.1f))
+
+ assertTransition(
+ currentScene = SceneC,
+ fromScene = SceneC,
+ toScene = SceneA,
+ isUserInputOngoing = true,
+ )
+ assertThat(transitionState).isNotSameInstanceAs(firstTransition)
}
}
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt
index 9403358..d81631a 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt
@@ -21,6 +21,9 @@
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.size
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.platform.LocalViewConfiguration
@@ -63,7 +66,10 @@
/** The content under test. */
@Composable
- private fun TestContent(layoutState: SceneTransitionLayoutState) {
+ private fun TestContent(
+ layoutState: SceneTransitionLayoutState,
+ swipesEnabled: () -> Boolean = { true },
+ ) {
SceneTransitionLayout(
state = layoutState,
modifier = Modifier.size(LayoutWidth, LayoutHeight).testTag(TestElements.Foo.debugName),
@@ -71,28 +77,35 @@
scene(
TestScenes.SceneA,
userActions =
- mapOf(
- Swipe.Left to TestScenes.SceneB,
- Swipe.Down to TestScenes.SceneC,
- ),
+ if (swipesEnabled())
+ mapOf(
+ Swipe.Left to TestScenes.SceneB,
+ Swipe.Down to TestScenes.SceneC,
+ Swipe.Up to TestScenes.SceneB,
+ )
+ else emptyMap(),
) {
Box(Modifier.fillMaxSize())
}
scene(
TestScenes.SceneB,
- userActions = mapOf(Swipe.Right to TestScenes.SceneA),
+ userActions =
+ if (swipesEnabled()) mapOf(Swipe.Right to TestScenes.SceneA) else emptyMap(),
) {
Box(Modifier.fillMaxSize())
}
scene(
TestScenes.SceneC,
userActions =
- mapOf(
- Swipe.Down to TestScenes.SceneA,
- Swipe(SwipeDirection.Down, pointerCount = 2) to TestScenes.SceneB,
- Swipe(SwipeDirection.Right, fromSource = Edge.Left) to TestScenes.SceneB,
- Swipe(SwipeDirection.Down, fromSource = Edge.Top) to TestScenes.SceneB,
- ),
+ if (swipesEnabled())
+ mapOf(
+ Swipe.Down to TestScenes.SceneA,
+ Swipe(SwipeDirection.Down, pointerCount = 2) to TestScenes.SceneB,
+ Swipe(SwipeDirection.Right, fromSource = Edge.Left) to
+ TestScenes.SceneB,
+ Swipe(SwipeDirection.Down, fromSource = Edge.Top) to TestScenes.SceneB,
+ )
+ else emptyMap(),
) {
Box(Modifier.fillMaxSize())
}
@@ -357,7 +370,7 @@
// detected as a drag event.
var touchSlop = 0f
- val layoutState = MutableSceneTransitionLayoutState(TestScenes.SceneA)
+ val layoutState = layoutState()
val verticalSwipeDistance = 50.dp
assertThat(verticalSwipeDistance).isNotEqualTo(LayoutHeight)
@@ -392,4 +405,74 @@
assertThat(transition).isNotNull()
assertThat(transition!!.progress).isEqualTo(0.5f)
}
+
+ @Test
+ fun swipeByTouchSlop() {
+ val layoutState = layoutState()
+ var touchSlop = 0f
+ rule.setContent {
+ touchSlop = LocalViewConfiguration.current.touchSlop
+ TestContent(layoutState)
+ }
+
+ // Swipe down by exactly touchSlop, so that the drag overSlop is 0f.
+ rule.onRoot().performTouchInput {
+ down(middle)
+ moveBy(Offset(0f, touchSlop), delayMillis = 1_000)
+ }
+
+ // We should still correctly compute that we are swiping down to scene C.
+ var transition = layoutState.currentTransition
+ assertThat(transition).isNotNull()
+ assertThat(transition?.toScene).isEqualTo(TestScenes.SceneC)
+
+ // Release the finger, animating back to scene A.
+ rule.onRoot().performTouchInput { up() }
+ rule.waitForIdle()
+ assertThat(layoutState.currentTransition).isNull()
+ assertThat(layoutState.transitionState.currentScene).isEqualTo(TestScenes.SceneA)
+
+ // Swipe up by exactly touchSlop, so that the drag overSlop is 0f.
+ rule.onRoot().performTouchInput {
+ down(middle)
+ moveBy(Offset(0f, -touchSlop), delayMillis = 1_000)
+ }
+
+ // We should still correctly compute that we are swiping up to scene B.
+ transition = layoutState.currentTransition
+ assertThat(transition).isNotNull()
+ assertThat(transition?.toScene).isEqualTo(TestScenes.SceneB)
+ }
+
+ @Test
+ fun swipeEnabledLater() {
+ val layoutState = MutableSceneTransitionLayoutState(TestScenes.SceneA)
+ var swipesEnabled by mutableStateOf(false)
+ var touchSlop = 0f
+ rule.setContent {
+ touchSlop = LocalViewConfiguration.current.touchSlop
+ TestContent(layoutState, swipesEnabled = { swipesEnabled })
+ }
+
+ // Drag down from the middle. This should not do anything, because swipes are disabled.
+ rule.onRoot().performTouchInput {
+ down(middle)
+ moveBy(Offset(0f, touchSlop), delayMillis = 1_000)
+ }
+ assertThat(layoutState.currentTransition).isNull()
+
+ // Release finger.
+ rule.onRoot().performTouchInput { up() }
+
+ // Enable swipes.
+ swipesEnabled = true
+ rule.waitForIdle()
+
+ // Drag down from the middle. Now it should start a transition.
+ rule.onRoot().performTouchInput {
+ down(middle)
+ moveBy(Offset(0f, touchSlop), delayMillis = 1_000)
+ }
+ assertThat(layoutState.currentTransition).isNotNull()
+ }
}
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/TransitionDslTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/TransitionDslTest.kt
index ef72992..140baca 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/TransitionDslTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/TransitionDslTest.kt
@@ -18,6 +18,7 @@
import androidx.compose.animation.core.SpringSpec
import androidx.compose.animation.core.TweenSpec
+import androidx.compose.animation.core.spring
import androidx.compose.animation.core.tween
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.compose.animation.scene.transformation.Transformation
@@ -188,6 +189,40 @@
)
}
+ @Test
+ fun springSpec() {
+ val defaultSpec = spring<Float>(stiffness = 1f)
+ val specFromAToC = spring<Float>(stiffness = 2f)
+ val transitions = transitions {
+ defaultSwipeSpec = defaultSpec
+
+ from(TestScenes.SceneA, to = TestScenes.SceneB) {
+ // Default swipe spec.
+ }
+ from(TestScenes.SceneA, to = TestScenes.SceneC) { swipeSpec = specFromAToC }
+ }
+
+ assertThat(transitions.defaultSwipeSpec).isSameInstanceAs(defaultSpec)
+
+ // A => B does not have a custom spec.
+ assertThat(
+ transitions
+ .transitionSpec(from = TestScenes.SceneA, to = TestScenes.SceneB)
+ .transformationSpec()
+ .swipeSpec
+ )
+ .isNull()
+
+ // A => C has a custom swipe spec.
+ assertThat(
+ transitions
+ .transitionSpec(from = TestScenes.SceneA, to = TestScenes.SceneC)
+ .transformationSpec()
+ .swipeSpec
+ )
+ .isSameInstanceAs(specFromAToC)
+ }
+
companion object {
private val TRANSFORMATION_RANGE =
Correspondence.transforming<Transformation, TransformationRange?>(
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModelTest.kt
index c6d612d..c193d14 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModelTest.kt
@@ -208,45 +208,13 @@
}
@Test
- fun onImeVisibilityChanged_false_doesNothing() =
+ fun onImeDismissed() =
testScope.runTest {
val events by collectValues(bouncerInteractor.onImeHiddenByUser)
assertThat(events).isEmpty()
- underTest.onImeVisibilityChanged(isVisible = false)
- assertThat(events).isEmpty()
- }
-
- @Test
- fun onImeVisibilityChanged_falseAfterTrue_emitsOnImeHiddenByUserEvent() =
- testScope.runTest {
- val events by collectValues(bouncerInteractor.onImeHiddenByUser)
- assertThat(events).isEmpty()
-
- underTest.onImeVisibilityChanged(isVisible = true)
- assertThat(events).isEmpty()
-
- underTest.onImeVisibilityChanged(isVisible = false)
+ underTest.onImeDismissed()
assertThat(events).hasSize(1)
-
- underTest.onImeVisibilityChanged(isVisible = true)
- assertThat(events).hasSize(1)
-
- underTest.onImeVisibilityChanged(isVisible = false)
- assertThat(events).hasSize(2)
- }
-
- @Test
- fun onImeVisibilityChanged_falseAfterTrue_whileLockedOut_doesNothing() =
- testScope.runTest {
- val events by collectValues(bouncerInteractor.onImeHiddenByUser)
- assertThat(events).isEmpty()
- underTest.onImeVisibilityChanged(isVisible = true)
- setLockout(true)
-
- underTest.onImeVisibilityChanged(isVisible = false)
-
- assertThat(events).isEmpty()
}
@Test
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt
index a083e7c..ee01bf9 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt
@@ -125,7 +125,7 @@
keyguardRepository.setIsEncryptedOrLockdown(false)
userRepository.setSelectedUserInfo(mainUser)
keyguardRepository.setKeyguardShowing(true)
- runCurrent()
+ communalRepository.setCommunalEnabledState(true)
assertThat(isAvailable).isTrue()
}
@@ -138,7 +138,8 @@
keyguardRepository.setIsEncryptedOrLockdown(true)
userRepository.setSelectedUserInfo(mainUser)
- runCurrent()
+ keyguardRepository.setKeyguardShowing(true)
+ communalRepository.setCommunalEnabledState(true)
assertThat(isAvailable).isFalse()
}
@@ -152,7 +153,7 @@
keyguardRepository.setIsEncryptedOrLockdown(false)
userRepository.setSelectedUserInfo(secondaryUser)
keyguardRepository.setKeyguardShowing(true)
- runCurrent()
+ communalRepository.setCommunalEnabledState(true)
assertThat(isAvailable).isFalse()
}
@@ -166,12 +167,26 @@
keyguardRepository.setIsEncryptedOrLockdown(false)
userRepository.setSelectedUserInfo(mainUser)
keyguardRepository.setDreaming(true)
- runCurrent()
+ communalRepository.setCommunalEnabledState(true)
assertThat(isAvailable).isTrue()
}
@Test
+ fun isCommunalAvailable_communalDisabled_false() =
+ testScope.runTest {
+ val isAvailable by collectLastValue(underTest.isCommunalAvailable)
+ assertThat(isAvailable).isFalse()
+
+ keyguardRepository.setIsEncryptedOrLockdown(false)
+ userRepository.setSelectedUserInfo(mainUser)
+ keyguardRepository.setKeyguardShowing(true)
+ communalRepository.setCommunalEnabledState(false)
+
+ assertThat(isAvailable).isFalse()
+ }
+
+ @Test
fun widget_tutorialCompletedAndWidgetsAvailable_showWidgetContent() =
testScope.runTest {
// Keyguard showing, and tutorial completed.
@@ -633,6 +648,14 @@
verify(editWidgetsActivityStarter).startActivity()
}
+ @Test
+ fun showWidgetEditor_withPreselectedKey_startsActivity() =
+ testScope.runTest {
+ val widgetKey = CommunalContentModel.KEY.widget(123)
+ underTest.showWidgetEditor(preselectedKey = widgetKey)
+ verify(editWidgetsActivityStarter).startActivity(widgetKey)
+ }
+
private fun smartspaceTimer(id: String, timestamp: Long = 0L): SmartspaceTarget {
val timer = mock(SmartspaceTarget::class.java)
whenever(timer.smartspaceTargetId).thenReturn(id)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalTutorialInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalTutorialInteractorTest.kt
index 352463f..6c87e0f 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalTutorialInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalTutorialInteractorTest.kt
@@ -34,20 +34,15 @@
import com.android.systemui.testKosmos
import com.android.systemui.user.data.repository.FakeUserRepository
import com.android.systemui.user.data.repository.fakeUserRepository
-import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
-import org.mockito.Mock
-import org.mockito.MockitoAnnotations
@SmallTest
@RunWith(AndroidJUnit4::class)
class CommunalTutorialInteractorTest : SysuiTestCase() {
- @Mock lateinit var user: UserInfo
-
private val kosmos = testKosmos()
private val testScope = kosmos.testScope
@@ -60,14 +55,14 @@
@Before
fun setUp() {
- MockitoAnnotations.initMocks(this)
-
keyguardRepository = kosmos.fakeKeyguardRepository
communalTutorialRepository = kosmos.fakeCommunalTutorialRepository
communalRepository = kosmos.fakeCommunalRepository
communalInteractor = kosmos.communalInteractor
userRepository = kosmos.fakeUserRepository
+ userRepository.setUserInfos(listOf(MAIN_USER_INFO))
+
underTest = kosmos.communalTutorialInteractor
}
@@ -204,12 +199,17 @@
private suspend fun setCommunalAvailable(available: Boolean) {
if (available) {
communalRepository.setIsCommunalEnabled(true)
+ communalRepository.setCommunalEnabledState(true)
keyguardRepository.setIsEncryptedOrLockdown(false)
- whenever(user.isMain).thenReturn(true)
- userRepository.setUserInfos(listOf(user))
- userRepository.setSelectedUserInfo(user)
+ userRepository.setSelectedUserInfo(MAIN_USER_INFO)
+ keyguardRepository.setKeyguardShowing(true)
} else {
- keyguardRepository.setIsEncryptedOrLockdown(true)
+ communalRepository.setIsCommunalEnabled(false)
+ communalRepository.setCommunalEnabledState(false)
}
}
+
+ private companion object {
+ val MAIN_USER_INFO = UserInfo(0, "primary", UserInfo.FLAG_MAIN)
+ }
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt
index a2dec5f..273d1cd 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt
@@ -129,6 +129,19 @@
}
@Test
+ fun selectedKey_onReorderWidgets_isCleared() =
+ testScope.runTest {
+ val selectedKey by collectLastValue(underTest.selectedKey)
+
+ val key = CommunalContentModel.KEY.widget(123)
+ underTest.setSelectedKey(key)
+ assertThat(selectedKey).isEqualTo(key)
+
+ underTest.onReorderWidgetStart()
+ assertThat(selectedKey).isNull()
+ }
+
+ @Test
fun reorderWidget_uiEventLogging_start() {
underTest.onReorderWidgetStart()
verify(uiEventLogger).log(CommunalUiEvent.COMMUNAL_HUB_REORDER_WIDGET_START)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt
index c814f3f..0723e83 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt
@@ -27,6 +27,7 @@
import com.android.systemui.communal.data.repository.FakeCommunalTutorialRepository
import com.android.systemui.communal.data.repository.FakeCommunalWidgetRepository
import com.android.systemui.communal.data.repository.fakeCommunalMediaRepository
+import com.android.systemui.communal.data.repository.fakeCommunalRepository
import com.android.systemui.communal.data.repository.fakeCommunalTutorialRepository
import com.android.systemui.communal.data.repository.fakeCommunalWidgetRepository
import com.android.systemui.communal.domain.interactor.communalInteractor
@@ -90,6 +91,8 @@
mediaRepository = kosmos.fakeCommunalMediaRepository
userRepository = kosmos.fakeUserRepository
+ kosmos.fakeCommunalRepository.setCommunalEnabledState(true)
+
underTest =
CommunalViewModel(
testScope,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/widgets/CommunalAppWidgetHostStartableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/widgets/CommunalAppWidgetHostStartableTest.kt
index 112b0c7..a3654b6 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/widgets/CommunalAppWidgetHostStartableTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/widgets/CommunalAppWidgetHostStartableTest.kt
@@ -20,6 +20,7 @@
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.communal.data.repository.fakeCommunalRepository
import com.android.systemui.communal.domain.interactor.communalInteractor
import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
import com.android.systemui.kosmos.applicationCoroutineScope
@@ -121,9 +122,10 @@
private suspend fun setCommunalAvailable(available: Boolean) =
with(kosmos) {
- fakeKeyguardRepository.setIsEncryptedOrLockdown(!available)
+ fakeKeyguardRepository.setIsEncryptedOrLockdown(false)
fakeUserRepository.setSelectedUserInfo(MAIN_USER_INFO)
fakeKeyguardRepository.setKeyguardShowing(true)
+ fakeCommunalRepository.setCommunalEnabledState(available)
}
private companion object {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt
index 78ae8b1..c01c79d 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt
@@ -574,7 +574,7 @@
@Test
fun isEncryptedOrLockdown() =
- testScope.runTest {
+ TestScope(mainDispatcher).runTest {
whenever(userTracker.userId).thenReturn(0)
whenever(keyguardUpdateMonitor.isEncryptedOrLockdown(0)).thenReturn(true)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt
index 34f703b..db414b7 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt
@@ -27,6 +27,7 @@
import com.android.systemui.common.shared.model.ContentDescription
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.coroutines.collectValues
import com.android.systemui.dock.DockManager
import com.android.systemui.dock.DockManagerFake
import com.android.systemui.flags.FakeFeatureFlags
@@ -49,16 +50,17 @@
import com.android.systemui.res.R
import com.android.systemui.settings.UserFileManager
import com.android.systemui.settings.UserTracker
+import com.android.systemui.shade.domain.interactor.ShadeInteractor
import com.android.systemui.shade.domain.interactor.shadeInteractor
import com.android.systemui.shared.keyguard.shared.model.KeyguardQuickAffordanceSlots
import com.android.systemui.statusbar.policy.KeyguardStateController
-import com.android.systemui.testKosmos
import com.android.systemui.util.FakeSharedPreferences
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
import com.android.systemui.util.settings.FakeSettings
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent
@@ -82,6 +84,7 @@
@Mock private lateinit var activityStarter: ActivityStarter
@Mock private lateinit var launchAnimator: DialogLaunchAnimator
@Mock private lateinit var devicePolicyManager: DevicePolicyManager
+ @Mock private lateinit var shadeInteractor: ShadeInteractor
@Mock private lateinit var logger: KeyguardQuickAffordancesMetricsLogger
private lateinit var underTest: KeyguardQuickAffordanceInteractor
@@ -95,8 +98,6 @@
private lateinit var dockManager: DockManagerFake
private lateinit var biometricSettingsRepository: FakeBiometricSettingsRepository
- private val kosmos = testKosmos()
-
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
@@ -183,7 +184,7 @@
underTest =
KeyguardQuickAffordanceInteractor(
keyguardInteractor = withDeps.keyguardInteractor,
- shadeInteractor = kosmos.shadeInteractor,
+ shadeInteractor = shadeInteractor,
lockPatternUtils = lockPatternUtils,
keyguardStateController = keyguardStateController,
userTracker = userTracker,
@@ -198,6 +199,8 @@
backgroundDispatcher = testDispatcher,
appContext = context,
)
+
+ whenever(shadeInteractor.anyExpansion).thenReturn(MutableStateFlow(0f))
}
@Test
@@ -344,6 +347,25 @@
}
@Test
+ fun quickAffordance_updateOncePerShadeExpansion() =
+ testScope.runTest {
+ val shadeExpansion = MutableStateFlow(0f)
+ whenever(shadeInteractor.anyExpansion).thenReturn(shadeExpansion)
+
+ val collectedValue by
+ collectValues(
+ underTest.quickAffordance(KeyguardQuickAffordancePosition.BOTTOM_START)
+ )
+
+ val initialSize = collectedValue.size
+ for (i in 0..10) {
+ shadeExpansion.value = i / 10f
+ }
+
+ assertThat(collectedValue.size).isEqualTo(initialSize + 1)
+ }
+
+ @Test
fun quickAffordanceAlwaysVisible_notVisible_restrictedByPolicyManager() =
testScope.runTest {
whenever(devicePolicyManager.getKeyguardDisabledFeatures(null, userTracker.userId))
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/data/repository/AutoAddSettingsRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/data/repository/AutoAddSettingsRepositoryTest.kt
index d277fca..1545e74 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/data/repository/AutoAddSettingsRepositoryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/data/repository/AutoAddSettingsRepositoryTest.kt
@@ -16,6 +16,7 @@
package com.android.systemui.qs.pipeline.data.repository
+import android.platform.test.annotations.EnabledOnRavenwood
import android.provider.Settings
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
@@ -38,6 +39,7 @@
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
+@EnabledOnRavenwood
@RunWith(AndroidJUnit4::class)
class AutoAddSettingsRepositoryTest : SysuiTestCase() {
private val secureSettings = FakeSettings()
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/data/repository/CustomTileAddedSharedPreferencesRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/data/repository/CustomTileAddedSharedPreferencesRepositoryTest.kt
index 3db676d..ee7a97a 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/data/repository/CustomTileAddedSharedPreferencesRepositoryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/data/repository/CustomTileAddedSharedPreferencesRepositoryTest.kt
@@ -18,6 +18,7 @@
import android.content.ComponentName
import android.content.SharedPreferences
+import android.platform.test.annotations.EnabledOnRavenwood
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
@@ -29,6 +30,7 @@
import org.junit.runner.RunWith
@SmallTest
+@EnabledOnRavenwood
@RunWith(AndroidJUnit4::class)
class CustomTileAddedSharedPreferencesRepositoryTest : SysuiTestCase() {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/data/repository/TileSpecSettingsRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/data/repository/TileSpecSettingsRepositoryTest.kt
index f7c3b21..3418977 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/data/repository/TileSpecSettingsRepositoryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/data/repository/TileSpecSettingsRepositoryTest.kt
@@ -16,6 +16,7 @@
package com.android.systemui.qs.pipeline.data.repository
+import android.platform.test.annotations.EnabledOnRavenwood
import android.provider.Settings
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
@@ -39,6 +40,7 @@
import org.mockito.MockitoAnnotations
@SmallTest
+@EnabledOnRavenwood
@RunWith(AndroidJUnit4::class)
@OptIn(ExperimentalCoroutinesApi::class)
class TileSpecSettingsRepositoryTest : SysuiTestCase() {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/data/repository/TilesSettingConverterTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/data/repository/TilesSettingConverterTest.kt
index 9516c21..9e99fc0 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/data/repository/TilesSettingConverterTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/data/repository/TilesSettingConverterTest.kt
@@ -1,5 +1,6 @@
package com.android.systemui.qs.pipeline.data.repository
+import android.platform.test.annotations.EnabledOnRavenwood
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
@@ -9,6 +10,7 @@
import org.junit.runner.RunWith
@SmallTest
+@EnabledOnRavenwood
@RunWith(AndroidJUnit4::class)
class TilesSettingConverterTest : SysuiTestCase() {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/data/repository/UserAutoAddRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/data/repository/UserAutoAddRepositoryTest.kt
index 36e860e..1ca3c06 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/data/repository/UserAutoAddRepositoryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/data/repository/UserAutoAddRepositoryTest.kt
@@ -1,5 +1,6 @@
package com.android.systemui.qs.pipeline.data.repository
+import android.platform.test.annotations.EnabledOnRavenwood
import android.provider.Settings
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
@@ -24,6 +25,7 @@
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
+@EnabledOnRavenwood
@RunWith(AndroidJUnit4::class)
class UserAutoAddRepositoryTest : SysuiTestCase() {
private val secureSettings = FakeSettings()
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/data/repository/UserTileSpecRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/data/repository/UserTileSpecRepositoryTest.kt
index d4a9fab..58fc109 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/data/repository/UserTileSpecRepositoryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/data/repository/UserTileSpecRepositoryTest.kt
@@ -1,5 +1,6 @@
package com.android.systemui.qs.pipeline.data.repository
+import android.platform.test.annotations.EnabledOnRavenwood
import android.provider.Settings
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
@@ -23,6 +24,7 @@
import org.mockito.MockitoAnnotations
@SmallTest
+@EnabledOnRavenwood
@OptIn(ExperimentalCoroutinesApi::class)
@RunWith(AndroidJUnit4::class)
class UserTileSpecRepositoryTest : SysuiTestCase() {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/data/restoreprocessors/WorkTileRestoreProcessorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/data/restoreprocessors/WorkTileRestoreProcessorTest.kt
index 30d1822..57bb77f 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/data/restoreprocessors/WorkTileRestoreProcessorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/data/restoreprocessors/WorkTileRestoreProcessorTest.kt
@@ -17,6 +17,7 @@
package com.android.systemui.qs.pipeline.data.restoreprocessors
import android.os.UserHandle
+import android.platform.test.annotations.EnabledOnRavenwood
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
@@ -31,6 +32,7 @@
import org.junit.runner.RunWith
@SmallTest
+@EnabledOnRavenwood
@RunWith(AndroidJUnit4::class)
@OptIn(ExperimentalCoroutinesApi::class)
class WorkTileRestoreProcessorTest : SysuiTestCase() {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/AutoAddableSettingListTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/AutoAddableSettingListTest.kt
index 4454a3c..f185ed5 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/AutoAddableSettingListTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/AutoAddableSettingListTest.kt
@@ -17,6 +17,7 @@
package com.android.systemui.qs.pipeline.domain.autoaddable
import android.content.ComponentName
+import android.platform.test.annotations.EnabledOnRavenwood
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.res.R
@@ -28,6 +29,7 @@
import org.junit.runner.RunWith
@SmallTest
+@EnabledOnRavenwood
@RunWith(AndroidJUnit4::class)
class AutoAddableSettingListTest : SysuiTestCase() {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/AutoAddableSettingTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/AutoAddableSettingTest.kt
index d153e9d..cfb84a7 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/AutoAddableSettingTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/AutoAddableSettingTest.kt
@@ -16,6 +16,7 @@
package com.android.systemui.qs.pipeline.domain.autoaddable
+import android.platform.test.annotations.EnabledOnRavenwood
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
@@ -35,6 +36,7 @@
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
+@EnabledOnRavenwood
@RunWith(AndroidJUnit4::class)
class AutoAddableSettingTest : SysuiTestCase() {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/CallbackControllerAutoAddableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/CallbackControllerAutoAddableTest.kt
index ec139e4..ea8d873 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/CallbackControllerAutoAddableTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/CallbackControllerAutoAddableTest.kt
@@ -16,6 +16,7 @@
package com.android.systemui.qs.pipeline.domain.autoaddable
+import android.platform.test.annotations.EnabledOnRavenwood
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
@@ -35,6 +36,7 @@
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
+@EnabledOnRavenwood
@RunWith(AndroidJUnit4::class)
class CallbackControllerAutoAddableTest : SysuiTestCase() {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/CastAutoAddableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/CastAutoAddableTest.kt
index 4fae532..9bb591e 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/CastAutoAddableTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/CastAutoAddableTest.kt
@@ -16,6 +16,7 @@
package com.android.systemui.qs.pipeline.domain.autoaddable
+import android.platform.test.annotations.EnabledOnRavenwood
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
@@ -41,6 +42,7 @@
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
+@EnabledOnRavenwood
@RunWith(AndroidJUnit4::class)
class CastAutoAddableTest : SysuiTestCase() {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/DataSaverAutoAddableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/DataSaverAutoAddableTest.kt
index 9e2d1f8..b925b27 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/DataSaverAutoAddableTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/DataSaverAutoAddableTest.kt
@@ -16,6 +16,7 @@
package com.android.systemui.qs.pipeline.domain.autoaddable
+import android.platform.test.annotations.EnabledOnRavenwood
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
@@ -40,6 +41,7 @@
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
+@EnabledOnRavenwood
@RunWith(AndroidJUnit4::class)
class DataSaverAutoAddableTest : SysuiTestCase() {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/DeviceControlsAutoAddableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/DeviceControlsAutoAddableTest.kt
index 0116bd9..188c6a9 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/DeviceControlsAutoAddableTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/DeviceControlsAutoAddableTest.kt
@@ -16,6 +16,7 @@
package com.android.systemui.qs.pipeline.domain.autoaddable
+import android.platform.test.annotations.EnabledOnRavenwood
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
@@ -43,6 +44,7 @@
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
+@EnabledOnRavenwood
@RunWith(AndroidJUnit4::class)
class DeviceControlsAutoAddableTest : SysuiTestCase() {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/HotspotAutoAddableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/HotspotAutoAddableTest.kt
index e7ea9a6..02699dd 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/HotspotAutoAddableTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/HotspotAutoAddableTest.kt
@@ -16,6 +16,7 @@
package com.android.systemui.qs.pipeline.domain.autoaddable
+import android.platform.test.annotations.EnabledOnRavenwood
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
@@ -40,6 +41,7 @@
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
+@EnabledOnRavenwood
@RunWith(AndroidJUnit4::class)
class HotspotAutoAddableTest : SysuiTestCase() {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/ReduceBrightColorsAutoAddableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/ReduceBrightColorsAutoAddableTest.kt
index 19ac63c..6d6fd75 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/ReduceBrightColorsAutoAddableTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/ReduceBrightColorsAutoAddableTest.kt
@@ -16,6 +16,7 @@
package com.android.systemui.qs.pipeline.domain.autoaddable
+import android.platform.test.annotations.EnabledOnRavenwood
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
@@ -43,6 +44,7 @@
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
+@EnabledOnRavenwood
@RunWith(AndroidJUnit4::class)
class ReduceBrightColorsAutoAddableTest : SysuiTestCase() {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/SafetyCenterAutoAddableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/SafetyCenterAutoAddableTest.kt
index d645ee3..633e494 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/SafetyCenterAutoAddableTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/SafetyCenterAutoAddableTest.kt
@@ -18,6 +18,7 @@
import android.content.ComponentName
import android.content.pm.PackageManager
+import android.platform.test.annotations.EnabledOnRavenwood
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.res.R
@@ -51,6 +52,7 @@
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
+@EnabledOnRavenwood
@RunWith(AndroidJUnit4::class)
class SafetyCenterAutoAddableTest : SysuiTestCase() {
private val testDispatcher = StandardTestDispatcher()
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/WalletAutoAddableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/WalletAutoAddableTest.kt
index 83ff35d..c5c76eb 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/WalletAutoAddableTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/autoaddable/WalletAutoAddableTest.kt
@@ -16,6 +16,7 @@
package com.android.systemui.qs.pipeline.domain.autoaddable
+import android.platform.test.annotations.EnabledOnRavenwood
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
@@ -37,6 +38,7 @@
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
+@EnabledOnRavenwood
@RunWith(AndroidJUnit4::class)
class WalletAutoAddableTest : SysuiTestCase() {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/interactor/AutoAddInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/interactor/AutoAddInteractorTest.kt
index 54b03a9..2ea12ef 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/interactor/AutoAddInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/interactor/AutoAddInteractorTest.kt
@@ -16,6 +16,7 @@
package com.android.systemui.qs.pipeline.domain.interactor
+import android.platform.test.annotations.EnabledOnRavenwood
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
@@ -46,6 +47,7 @@
import org.mockito.MockitoAnnotations
@SmallTest
+@EnabledOnRavenwood
@RunWith(AndroidJUnit4::class)
@OptIn(ExperimentalCoroutinesApi::class)
class AutoAddInteractorTest : SysuiTestCase() {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/interactor/PanelInteractorImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/interactor/PanelInteractorImplTest.kt
index 0d97115..d38c19b 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/interactor/PanelInteractorImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/interactor/PanelInteractorImplTest.kt
@@ -15,6 +15,7 @@
*/
package com.android.systemui.qs.pipeline.domain.interactor
+import android.platform.test.annotations.EnabledOnRavenwood
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
@@ -28,6 +29,7 @@
@RunWith(AndroidJUnit4::class)
@SmallTest
+@EnabledOnRavenwood
class PanelInteractorImplTest : SysuiTestCase() {
@Mock private lateinit var shadeController: ShadeController
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/interactor/RestoreReconciliationInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/interactor/RestoreReconciliationInteractorTest.kt
index b2a9783..0b3144a 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/interactor/RestoreReconciliationInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/domain/interactor/RestoreReconciliationInteractorTest.kt
@@ -1,5 +1,6 @@
package com.android.systemui.qs.pipeline.domain.interactor
+import android.platform.test.annotations.EnabledOnRavenwood
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
@@ -26,6 +27,7 @@
@RunWith(AndroidJUnit4::class)
@SmallTest
+@EnabledOnRavenwood
class RestoreReconciliationInteractorTest : SysuiTestCase() {
private val tileSpecRepository = FakeTileSpecRepository()
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/shared/TileSpecTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/shared/TileSpecTest.kt
index 558e769..869ab6c 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/shared/TileSpecTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/pipeline/shared/TileSpecTest.kt
@@ -17,6 +17,7 @@
package com.android.systemui.qs.pipeline.shared
import android.content.ComponentName
+import android.platform.test.annotations.EnabledOnRavenwood
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
@@ -25,6 +26,7 @@
import org.junit.runner.RunWith
@SmallTest
+@EnabledOnRavenwood
@RunWith(AndroidJUnit4::class)
class TileSpecTest : SysuiTestCase() {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/base/actions/QSTileIntentUserInputHandlerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/base/actions/QSTileIntentUserInputHandlerTest.kt
index c104977..bf48784 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/base/actions/QSTileIntentUserInputHandlerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/base/actions/QSTileIntentUserInputHandlerTest.kt
@@ -24,6 +24,7 @@
import android.content.pm.PackageManager.ResolveInfoFlags
import android.content.pm.ResolveInfo
import android.os.UserHandle
+import android.platform.test.annotations.EnabledOnRavenwood
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
@@ -44,6 +45,7 @@
import org.mockito.MockitoAnnotations
@SmallTest
+@EnabledOnRavenwood
@RunWith(AndroidJUnit4::class)
class QSTileIntentUserInputHandlerTest : SysuiTestCase() {
@Mock private lateinit var packageManager: PackageManager
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/base/analytics/QSTileAnalyticsTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/base/analytics/QSTileAnalyticsTest.kt
index 9861606..fd09e3c 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/base/analytics/QSTileAnalyticsTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/base/analytics/QSTileAnalyticsTest.kt
@@ -16,6 +16,7 @@
package com.android.systemui.qs.tiles.base.analytics
+import android.platform.test.annotations.EnabledOnRavenwood
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.internal.logging.InstanceId
@@ -33,6 +34,7 @@
import org.mockito.MockitoAnnotations
@SmallTest
+@EnabledOnRavenwood
@RunWith(AndroidJUnit4::class)
class QSTileAnalyticsTest : SysuiTestCase() {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/base/interactor/DisabledByPolicyInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/base/interactor/DisabledByPolicyInteractorTest.kt
index 2bdc154..a1f885c 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/base/interactor/DisabledByPolicyInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/base/interactor/DisabledByPolicyInteractorTest.kt
@@ -20,6 +20,7 @@
import android.content.Context
import android.content.Intent
import android.os.UserHandle
+import android.platform.test.annotations.EnabledOnRavenwood
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.settingslib.RestrictedLockUtils
@@ -45,6 +46,7 @@
import org.mockito.MockitoAnnotations
@SmallTest
+@EnabledOnRavenwood
@RunWith(AndroidJUnit4::class)
class DisabledByPolicyInteractorTest : SysuiTestCase() {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/airplate/domain/interactor/AirplaneModeTileDataInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/airplate/domain/interactor/AirplaneModeTileDataInteractorTest.kt
index 937744d..89b9b7f 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/airplate/domain/interactor/AirplaneModeTileDataInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/airplate/domain/interactor/AirplaneModeTileDataInteractorTest.kt
@@ -17,6 +17,7 @@
package com.android.systemui.qs.tiles.impl.airplate.domain.interactor
import android.os.UserHandle
+import android.platform.test.annotations.EnabledOnRavenwood
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
@@ -36,6 +37,7 @@
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
+@EnabledOnRavenwood
@RunWith(AndroidJUnit4::class)
class AirplaneModeTileDataInteractorTest : SysuiTestCase() {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/airplate/domain/interactor/AirplaneModeTileUserActionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/airplate/domain/interactor/AirplaneModeTileUserActionInteractorTest.kt
index 81bde81..8982d81 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/airplate/domain/interactor/AirplaneModeTileUserActionInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/airplate/domain/interactor/AirplaneModeTileUserActionInteractorTest.kt
@@ -16,6 +16,7 @@
package com.android.systemui.qs.tiles.impl.airplate.domain.interactor
+import android.platform.test.annotations.EnabledOnRavenwood
import android.provider.Settings
import android.telephony.TelephonyManager
import androidx.test.ext.junit.runners.AndroidJUnit4
@@ -37,6 +38,7 @@
import org.junit.runner.RunWith
@SmallTest
+@EnabledOnRavenwood
@RunWith(AndroidJUnit4::class)
class AirplaneModeTileUserActionInteractorTest : SysuiTestCase() {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/interactor/ColorCorrectionTileDataInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/interactor/ColorCorrectionTileDataInteractorTest.kt
index 8c612ac..abaf808 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/interactor/ColorCorrectionTileDataInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/interactor/ColorCorrectionTileDataInteractorTest.kt
@@ -17,6 +17,7 @@
package com.android.systemui.qs.tiles.impl.colorcorrection.domain.interactor
import android.os.UserHandle
+import android.platform.test.annotations.EnabledOnRavenwood
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
@@ -35,6 +36,7 @@
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
+@EnabledOnRavenwood
@RunWith(AndroidJUnit4::class)
class ColorCorrectionTileDataInteractorTest : SysuiTestCase() {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/interactor/ColorCorrectionTileUserActionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/interactor/ColorCorrectionTileUserActionInteractorTest.kt
index 3049cc0..3bc53b27 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/interactor/ColorCorrectionTileUserActionInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/colorcorrection/domain/interactor/ColorCorrectionTileUserActionInteractorTest.kt
@@ -17,6 +17,7 @@
package com.android.systemui.qs.tiles.impl.colorcorrection.domain.interactor
import android.os.UserHandle
+import android.platform.test.annotations.EnabledOnRavenwood
import android.provider.Settings
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
@@ -32,6 +33,7 @@
import org.junit.runner.RunWith
@SmallTest
+@EnabledOnRavenwood
@RunWith(AndroidJUnit4::class)
class ColorCorrectionTileUserActionInteractorTest : SysuiTestCase() {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/flashlight/domain/interactor/FlashlightTileDataInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/flashlight/domain/interactor/FlashlightTileDataInteractorTest.kt
index 7f7490d..a9e39354 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/flashlight/domain/interactor/FlashlightTileDataInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/flashlight/domain/interactor/FlashlightTileDataInteractorTest.kt
@@ -17,6 +17,7 @@
package com.android.systemui.qs.tiles.impl.flashlight.domain.interactor
import android.os.UserHandle
+import android.platform.test.annotations.EnabledOnRavenwood
import android.testing.LeakCheck
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
@@ -37,6 +38,7 @@
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
+@EnabledOnRavenwood
@RunWith(AndroidJUnit4::class)
class FlashlightTileDataInteractorTest : SysuiTestCase() {
private lateinit var controller: FakeFlashlightController
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/inversion/domain/interactor/ColorInversionTileDataInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/inversion/domain/interactor/ColorInversionTileDataInteractorTest.kt
index 24c7bfb..75b07ee 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/inversion/domain/interactor/ColorInversionTileDataInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/inversion/domain/interactor/ColorInversionTileDataInteractorTest.kt
@@ -17,6 +17,7 @@
package com.android.systemui.qs.tiles.impl.inversion.domain.interactor
import android.os.UserHandle
+import android.platform.test.annotations.EnabledOnRavenwood
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
@@ -35,6 +36,7 @@
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
+@EnabledOnRavenwood
@RunWith(AndroidJUnit4::class)
class ColorInversionTileDataInteractorTest : SysuiTestCase() {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/inversion/domain/interactor/ColorInversionUserActionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/inversion/domain/interactor/ColorInversionUserActionInteractorTest.kt
index 99bae18..f574f79 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/inversion/domain/interactor/ColorInversionUserActionInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/inversion/domain/interactor/ColorInversionUserActionInteractorTest.kt
@@ -17,6 +17,7 @@
package com.android.systemui.qs.tiles.impl.inversion.domain.interactor
import android.os.UserHandle
+import android.platform.test.annotations.EnabledOnRavenwood
import android.provider.Settings
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
@@ -32,6 +33,7 @@
import org.junit.runner.RunWith
@SmallTest
+@EnabledOnRavenwood
@RunWith(AndroidJUnit4::class)
class ColorInversionUserActionInteractorTest : SysuiTestCase() {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/location/interactor/LocationTileDataInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/location/interactor/LocationTileDataInteractorTest.kt
index 8fdc93b..9adf57a 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/location/interactor/LocationTileDataInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/location/interactor/LocationTileDataInteractorTest.kt
@@ -17,6 +17,7 @@
package com.android.systemui.qs.tiles.impl.location.interactor
import android.os.UserHandle
+import android.platform.test.annotations.EnabledOnRavenwood
import android.testing.LeakCheck
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
@@ -38,6 +39,7 @@
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
+@EnabledOnRavenwood
@RunWith(AndroidJUnit4::class)
class LocationTileDataInteractorTest : SysuiTestCase() {
private lateinit var controller: FakeLocationController
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/location/interactor/LocationTileUserActionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/location/interactor/LocationTileUserActionInteractorTest.kt
index 0fb8ae6..8b21cb4 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/location/interactor/LocationTileUserActionInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/location/interactor/LocationTileUserActionInteractorTest.kt
@@ -16,6 +16,7 @@
package com.android.systemui.qs.tiles.impl.location.interactor
+import android.platform.test.annotations.EnabledOnRavenwood
import android.provider.Settings
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
@@ -42,6 +43,7 @@
import org.mockito.MockitoAnnotations
@SmallTest
+@EnabledOnRavenwood
@RunWith(AndroidJUnit4::class)
class LocationTileUserActionInteractorTest : SysuiTestCase() {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/saver/domain/DataSaverDialogDelegateTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/saver/domain/DataSaverDialogDelegateTest.kt
index 4b96251..f24723a 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/saver/domain/DataSaverDialogDelegateTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/saver/domain/DataSaverDialogDelegateTest.kt
@@ -17,6 +17,7 @@
package com.android.systemui.qs.tiles.impl.saver.domain
import android.content.SharedPreferences
+import android.platform.test.annotations.EnabledOnRavenwood
import android.testing.LeakCheck
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
@@ -37,6 +38,7 @@
/** Test [DataSaverDialogDelegate]. */
@SmallTest
+@EnabledOnRavenwood
@RunWith(AndroidJUnit4::class)
class DataSaverDialogDelegateTest : SysuiTestCase() {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/saver/domain/interactor/DataSaverTileDataInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/saver/domain/interactor/DataSaverTileDataInteractorTest.kt
index 819bd03..daee22d 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/saver/domain/interactor/DataSaverTileDataInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/saver/domain/interactor/DataSaverTileDataInteractorTest.kt
@@ -17,6 +17,7 @@
package com.android.systemui.qs.tiles.impl.saver.domain.interactor
import android.os.UserHandle
+import android.platform.test.annotations.EnabledOnRavenwood
import android.testing.LeakCheck
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
@@ -36,6 +37,7 @@
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
+@EnabledOnRavenwood
@RunWith(AndroidJUnit4::class)
class DataSaverTileDataInteractorTest : SysuiTestCase() {
private val controller: FakeDataSaverController = FakeDataSaverController(LeakCheck())
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/uimodenight/domain/UiModeNightTileUserActionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/uimodenight/domain/UiModeNightTileUserActionInteractorTest.kt
index 004ec62..eea6d16 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/uimodenight/domain/UiModeNightTileUserActionInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/uimodenight/domain/UiModeNightTileUserActionInteractorTest.kt
@@ -17,6 +17,7 @@
package com.android.systemui.qs.tiles.impl.uimodenight.domain
import android.app.UiModeManager
+import android.platform.test.annotations.EnabledOnRavenwood
import android.provider.Settings
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
@@ -39,6 +40,7 @@
import org.mockito.Mockito.verify
@SmallTest
+@EnabledOnRavenwood
@RunWith(AndroidJUnit4::class)
class UiModeNightTileUserActionInteractorTest : SysuiTestCase() {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/viewmodel/QSTileConfigProviderTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/viewmodel/QSTileConfigProviderTest.kt
index 5eca8ca..40971a8 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/viewmodel/QSTileConfigProviderTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/viewmodel/QSTileConfigProviderTest.kt
@@ -16,6 +16,7 @@
package com.android.systemui.qs.tiles.viewmodel
+import android.platform.test.annotations.EnabledOnRavenwood
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
@@ -27,6 +28,7 @@
import org.junit.runner.RunWith
@SmallTest
+@EnabledOnRavenwood
@RunWith(AndroidJUnit4::class)
class QSTileConfigProviderTest : SysuiTestCase() {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelTest.kt
index 3a0ebdb..a8bc8d6 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelTest.kt
@@ -17,6 +17,7 @@
package com.android.systemui.qs.tiles.viewmodel
import android.os.UserHandle
+import android.platform.test.annotations.EnabledOnRavenwood
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.MediumTest
import com.android.systemui.SysuiTestCase
@@ -50,6 +51,7 @@
import org.mockito.MockitoAnnotations
@MediumTest
+@EnabledOnRavenwood
@RunWith(AndroidJUnit4::class)
@OptIn(ExperimentalCoroutinesApi::class)
class QSTileViewModelTest : SysuiTestCase() {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelUserInputTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelUserInputTest.kt
index 22fb152..18cdd71 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelUserInputTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/viewmodel/QSTileViewModelUserInputTest.kt
@@ -16,6 +16,7 @@
package com.android.systemui.qs.tiles.viewmodel
+import android.platform.test.annotations.EnabledOnRavenwood
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.MediumTest
import com.android.settingslib.RestrictedLockUtils
@@ -53,6 +54,7 @@
/** Tests all possible [QSTileUserAction]s. If you need */
@MediumTest
+@EnabledOnRavenwood
@RunWith(AndroidJUnit4::class)
@OptIn(ExperimentalCoroutinesApi::class)
class QSTileViewModelUserInputTest : SysuiTestCase() {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/adapter/QSSceneAdapterTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/adapter/QSSceneAdapterTest.kt
index 18a7320..d1bc686 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/adapter/QSSceneAdapterTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/adapter/QSSceneAdapterTest.kt
@@ -16,6 +16,7 @@
package com.android.systemui.qs.ui.adapter
+import android.platform.test.annotations.EnabledOnRavenwood
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
@@ -25,6 +26,7 @@
import org.junit.runner.RunWith
@SmallTest
+@EnabledOnRavenwood
@RunWith(AndroidJUnit4::class)
class QSSceneAdapterTest : SysuiTestCase() {
@Test
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt
index 1e5ebd0..504ded3 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt
@@ -52,6 +52,7 @@
import com.android.systemui.kosmos.testScope
import com.android.systemui.media.controls.pipeline.MediaDataManager
import com.android.systemui.model.SysUiState
+import com.android.systemui.model.sceneContainerPlugin
import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setAsleepForTest
import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setAwakeForTest
import com.android.systemui.power.domain.interactor.powerInteractor
@@ -244,7 +245,7 @@
kosmos.fakeDeviceEntryRepository.setUnlocked(false)
val displayTracker = FakeDisplayTracker(context)
- val sysUiState = SysUiState(displayTracker)
+ val sysUiState = SysUiState(displayTracker, kosmos.sceneContainerPlugin)
val startable =
SceneContainerStartable(
applicationScope = testScope.backgroundScope,
@@ -775,14 +776,9 @@
}
/** Emulates the dismissal of the IME (soft keyboard). */
- private suspend fun TestScope.dismissIme(
- showImeBeforeDismissing: Boolean = true,
- ) {
+ private fun TestScope.dismissIme() {
(bouncerViewModel.authMethodViewModel.value as? PasswordBouncerViewModel)?.let {
- if (showImeBeforeDismissing) {
- it.onImeVisibilityChanged(true)
- }
- it.onImeVisibilityChanged(false)
+ it.onImeDismissed()
runCurrent()
}
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt
index bf99a86..942fbc2 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt
@@ -174,105 +174,6 @@
}
@Test
- fun transitioning_idle_false() =
- testScope.runTest {
- val transitionState =
- MutableStateFlow<ObservableTransitionState>(
- ObservableTransitionState.Idle(SceneKey.Shade)
- )
- val transitioning by
- collectLastValue(underTest.transitioning(SceneKey.Shade, SceneKey.Lockscreen))
- underTest.setTransitionState(transitionState)
-
- assertThat(transitioning).isFalse()
- }
-
- @Test
- fun transitioning_wrongFromScene_false() =
- testScope.runTest {
- val transitionState =
- MutableStateFlow<ObservableTransitionState>(
- ObservableTransitionState.Transition(
- fromScene = SceneKey.Gone,
- toScene = SceneKey.Lockscreen,
- progress = flowOf(0.5f),
- isInitiatedByUserInput = false,
- isUserInputOngoing = flowOf(false),
- )
- )
- val transitioning by
- collectLastValue(underTest.transitioning(SceneKey.Shade, SceneKey.Lockscreen))
- underTest.setTransitionState(transitionState)
-
- assertThat(transitioning).isFalse()
- }
-
- @Test
- fun transitioning_wrongToScene_false() =
- testScope.runTest {
- val transitionState =
- MutableStateFlow<ObservableTransitionState>(
- ObservableTransitionState.Transition(
- fromScene = SceneKey.Shade,
- toScene = SceneKey.QuickSettings,
- progress = flowOf(0.5f),
- isInitiatedByUserInput = false,
- isUserInputOngoing = flowOf(false),
- )
- )
- underTest.setTransitionState(transitionState)
-
- assertThat(underTest.transitioning(SceneKey.Shade, SceneKey.Lockscreen).value).isFalse()
- }
-
- @Test
- fun transitioning_correctFromAndToScenes_true() =
- testScope.runTest {
- val transitionState =
- MutableStateFlow<ObservableTransitionState>(
- ObservableTransitionState.Transition(
- fromScene = SceneKey.Shade,
- toScene = SceneKey.Lockscreen,
- progress = flowOf(0.5f),
- isInitiatedByUserInput = false,
- isUserInputOngoing = flowOf(false),
- )
- )
- val transitioning by
- collectLastValue(underTest.transitioning(SceneKey.Shade, SceneKey.Lockscreen))
- underTest.setTransitionState(transitionState)
-
- assertThat(transitioning).isTrue()
- }
-
- @Test
- fun transitioning_updates() =
- testScope.runTest {
- val transitionState =
- MutableStateFlow<ObservableTransitionState>(
- ObservableTransitionState.Idle(SceneKey.Shade)
- )
- val transitioning by
- collectLastValue(underTest.transitioning(SceneKey.Shade, SceneKey.Lockscreen))
- underTest.setTransitionState(transitionState)
-
- assertThat(transitioning).isFalse()
-
- transitionState.value =
- ObservableTransitionState.Transition(
- fromScene = SceneKey.Shade,
- toScene = SceneKey.Lockscreen,
- progress = flowOf(0.5f),
- isInitiatedByUserInput = false,
- isUserInputOngoing = flowOf(false),
- )
- assertThat(transitioning).isTrue()
-
- transitionState.value = ObservableTransitionState.Idle(SceneKey.Lockscreen)
- assertThat(transitioning).isFalse()
- }
-
- @Test
fun isTransitionUserInputOngoing_idle_false() =
testScope.runTest {
val transitionState =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/domain/interactor/ShadeAnimationInteractorSceneContainerImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeAnimationInteractorSceneContainerImplTest.kt
similarity index 66%
rename from packages/SystemUI/tests/src/com/android/systemui/shade/domain/interactor/ShadeAnimationInteractorSceneContainerImplTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeAnimationInteractorSceneContainerImplTest.kt
index 6bbe900c..1ef07fa 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/domain/interactor/ShadeAnimationInteractorSceneContainerImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeAnimationInteractorSceneContainerImplTest.kt
@@ -16,71 +16,37 @@
package com.android.systemui.shade.domain.interactor
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
-import com.android.systemui.SysUITestComponent
-import com.android.systemui.SysUITestModule
import com.android.systemui.SysuiTestCase
-import com.android.systemui.TestMocksModule
-import com.android.systemui.collectLastValue
-import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.flags.FakeFeatureFlagsClassicModule
-import com.android.systemui.flags.Flags
-import com.android.systemui.runCurrent
-import com.android.systemui.runTest
-import com.android.systemui.scene.domain.interactor.SceneInteractor
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.scene.domain.interactor.sceneInteractor
import com.android.systemui.scene.shared.model.ObservableTransitionState
import com.android.systemui.scene.shared.model.SceneKey
-import com.android.systemui.statusbar.phone.DozeParameters
-import com.android.systemui.user.domain.UserDomainLayerModule
-import com.android.systemui.util.mockito.mock
+import com.android.systemui.testKosmos
import com.google.common.truth.Truth
-import dagger.BindsInstance
-import dagger.Component
+import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
import org.junit.Test
+import org.junit.runner.RunWith
+@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
+@RunWith(AndroidJUnit4::class)
class ShadeAnimationInteractorSceneContainerImplTest : SysuiTestCase() {
+ val kosmos = testKosmos()
+ val testScope = kosmos.testScope
+ val sceneInteractor = kosmos.sceneInteractor
- @SysUISingleton
- @Component(
- modules =
- [
- SysUITestModule::class,
- UserDomainLayerModule::class,
- ]
- )
- interface TestComponent : SysUITestComponent<ShadeAnimationInteractorSceneContainerImpl> {
- val sceneInteractor: SceneInteractor
-
- @Component.Factory
- interface Factory {
- fun create(
- @BindsInstance test: SysuiTestCase,
- featureFlags: FakeFeatureFlagsClassicModule,
- mocks: TestMocksModule,
- ): TestComponent
- }
- }
-
- private val dozeParameters: DozeParameters = mock()
-
- private val testComponent: TestComponent =
- DaggerShadeAnimationInteractorSceneContainerImplTest_TestComponent.factory()
- .create(
- test = this,
- featureFlags =
- FakeFeatureFlagsClassicModule { set(Flags.FULL_SCREEN_USER_SWITCHER, true) },
- mocks =
- TestMocksModule(
- dozeParameters = dozeParameters,
- ),
- )
+ val underTest = kosmos.shadeAnimationInteractorSceneContainerImpl
@Test
fun isAnyCloseAnimationRunning_qsToShade() =
- testComponent.runTest() {
+ testScope.runTest {
val actual by collectLastValue(underTest.isAnyCloseAnimationRunning)
// WHEN transitioning from QS to Shade
@@ -103,10 +69,10 @@
@Test
fun isAnyCloseAnimationRunning_qsToGone_userInputNotOngoing() =
- testComponent.runTest() {
+ testScope.runTest() {
val actual by collectLastValue(underTest.isAnyCloseAnimationRunning)
- // WHEN transitioning from QS to Gone with no ongoing user input
+ // WHEN transitioning from QS to Gone lwith no ongoing user input
val transitionState =
MutableStateFlow<ObservableTransitionState>(
ObservableTransitionState.Transition(
@@ -126,7 +92,7 @@
@Test
fun isAnyCloseAnimationRunning_qsToGone_userInputOngoing() =
- testComponent.runTest() {
+ testScope.runTest() {
val actual by collectLastValue(underTest.isAnyCloseAnimationRunning)
// WHEN transitioning from QS to Gone with user input ongoing
@@ -149,7 +115,7 @@
@Test
fun updateIsLaunchingActivity() =
- testComponent.runTest {
+ testScope.runTest {
Truth.assertThat(underTest.isLaunchingActivity.value).isEqualTo(false)
underTest.setIsLaunchingActivity(true)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImplTest.kt
similarity index 83%
rename from packages/SystemUI/tests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImplTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImplTest.kt
index 71a7420..4e82feb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImplTest.kt
@@ -19,124 +19,65 @@
import android.app.StatusBarManager.DISABLE2_NONE
import android.app.StatusBarManager.DISABLE2_NOTIFICATION_SHADE
import android.app.StatusBarManager.DISABLE2_QUICK_SETTINGS
-import android.content.pm.UserInfo
-import android.os.UserManager
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
-import com.android.systemui.SysUITestComponent
-import com.android.systemui.SysUITestModule
import com.android.systemui.SysuiTestCase
-import com.android.systemui.TestMocksModule
-import com.android.systemui.collectLastValue
-import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository
-import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.flags.FakeFeatureFlagsClassicModule
-import com.android.systemui.flags.Flags
-import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
-import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
+import com.android.systemui.common.ui.data.repository.fakeConfigurationRepository
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
+import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
import com.android.systemui.keyguard.shared.model.DozeStateModel
import com.android.systemui.keyguard.shared.model.DozeTransitionModel
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.StatusBarState
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.shared.model.TransitionStep
-import com.android.systemui.power.data.repository.FakePowerRepository
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.power.data.repository.fakePowerRepository
import com.android.systemui.power.shared.model.WakeSleepReason
import com.android.systemui.power.shared.model.WakefulnessState
import com.android.systemui.res.R
-import com.android.systemui.runCurrent
-import com.android.systemui.runTest
-import com.android.systemui.scene.domain.interactor.SceneInteractor
-import com.android.systemui.shade.data.repository.FakeShadeRepository
+import com.android.systemui.scene.domain.interactor.sceneInteractor
+import com.android.systemui.shade.data.repository.fakeShadeRepository
import com.android.systemui.statusbar.disableflags.data.model.DisableFlagsModel
-import com.android.systemui.statusbar.disableflags.data.repository.FakeDisableFlagsRepository
-import com.android.systemui.statusbar.phone.DozeParameters
-import com.android.systemui.statusbar.policy.data.repository.FakeDeviceProvisioningRepository
-import com.android.systemui.statusbar.policy.data.repository.FakeUserSetupRepository
+import com.android.systemui.statusbar.disableflags.data.repository.fakeDisableFlagsRepository
+import com.android.systemui.statusbar.phone.dozeParameters
+import com.android.systemui.statusbar.policy.data.repository.fakeDeviceProvisioningRepository
+import com.android.systemui.statusbar.policy.data.repository.fakeUserSetupRepository
+import com.android.systemui.testKosmos
import com.android.systemui.user.data.model.UserSwitcherSettingsModel
-import com.android.systemui.user.data.repository.FakeUserRepository
-import com.android.systemui.user.domain.UserDomainLayerModule
-import com.android.systemui.util.mockito.mock
+import com.android.systemui.user.data.repository.fakeUserRepository
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
-import dagger.BindsInstance
-import dagger.Component
-import kotlinx.coroutines.runBlocking
-import org.junit.Before
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
import org.junit.Test
+import org.junit.runner.RunWith
+@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
+@RunWith(AndroidJUnit4::class)
class ShadeInteractorImplTest : SysuiTestCase() {
+ val kosmos = testKosmos()
+ val testScope = kosmos.testScope
+ val configurationRepository = kosmos.fakeConfigurationRepository
+ val deviceProvisioningRepository = kosmos.fakeDeviceProvisioningRepository
+ val disableFlagsRepository = kosmos.fakeDisableFlagsRepository
+ val keyguardRepository = kosmos.fakeKeyguardRepository
+ val keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository
+ val powerRepository = kosmos.fakePowerRepository
+ val sceneInteractor = kosmos.sceneInteractor
+ val shadeRepository = kosmos.fakeShadeRepository
+ val userRepository = kosmos.fakeUserRepository
+ val userSetupRepository = kosmos.fakeUserSetupRepository
+ val dozeParameters = kosmos.dozeParameters
- @SysUISingleton
- @Component(
- modules =
- [
- SysUITestModule::class,
- UserDomainLayerModule::class,
- ]
- )
- interface TestComponent : SysUITestComponent<ShadeInteractorImpl> {
-
- val configurationRepository: FakeConfigurationRepository
- val deviceProvisioningRepository: FakeDeviceProvisioningRepository
- val disableFlagsRepository: FakeDisableFlagsRepository
- val keyguardRepository: FakeKeyguardRepository
- val keyguardTransitionRepository: FakeKeyguardTransitionRepository
- val powerRepository: FakePowerRepository
- val sceneInteractor: SceneInteractor
- val shadeRepository: FakeShadeRepository
- val userRepository: FakeUserRepository
- val userSetupRepository: FakeUserSetupRepository
-
- @Component.Factory
- interface Factory {
- fun create(
- @BindsInstance test: SysuiTestCase,
- featureFlags: FakeFeatureFlagsClassicModule,
- mocks: TestMocksModule,
- ): TestComponent
- }
- }
-
- private val dozeParameters: DozeParameters = mock()
-
- private val testComponent: TestComponent =
- DaggerShadeInteractorImplTest_TestComponent.factory()
- .create(
- test = this,
- featureFlags =
- FakeFeatureFlagsClassicModule { set(Flags.FULL_SCREEN_USER_SWITCHER, true) },
- mocks =
- TestMocksModule(
- dozeParameters = dozeParameters,
- ),
- )
-
- @Before
- fun setUp() {
- runBlocking {
- val userInfos =
- listOf(
- UserInfo(
- /* id= */ 0,
- /* name= */ "zero",
- /* iconPath= */ "",
- /* flags= */ UserInfo.FLAG_PRIMARY or
- UserInfo.FLAG_ADMIN or
- UserInfo.FLAG_FULL,
- UserManager.USER_TYPE_FULL_SYSTEM,
- ),
- )
- testComponent.apply {
- userRepository.setUserInfos(userInfos)
- userRepository.setSelectedUserInfo(userInfos[0])
- }
- }
- }
+ val underTest = kosmos.shadeInteractorImpl
@Test
fun isShadeEnabled_matchesDisableFlagsRepo() =
- testComponent.runTest {
+ testScope.runTest {
val actual by collectLastValue(underTest.isShadeEnabled)
disableFlagsRepository.disableFlags.value =
@@ -150,7 +91,7 @@
@Test
fun isExpandToQsEnabled_deviceNotProvisioned_false() =
- testComponent.runTest {
+ testScope.runTest {
deviceProvisioningRepository.setDeviceProvisioned(false)
val actual by collectLastValue(underTest.isExpandToQsEnabled)
@@ -160,7 +101,7 @@
@Test
fun isExpandToQsEnabled_userNotSetupAndSimpleUserSwitcher_false() =
- testComponent.runTest {
+ testScope.runTest {
deviceProvisioningRepository.setDeviceProvisioned(true)
userSetupRepository.setUserSetUp(false)
@@ -173,7 +114,7 @@
@Test
fun isExpandToQsEnabled_shadeNotEnabled_false() =
- testComponent.runTest {
+ testScope.runTest {
deviceProvisioningRepository.setDeviceProvisioned(true)
userSetupRepository.setUserSetUp(true)
@@ -189,7 +130,7 @@
@Test
fun isExpandToQsEnabled_quickSettingsNotEnabled_false() =
- testComponent.runTest {
+ testScope.runTest {
deviceProvisioningRepository.setDeviceProvisioned(true)
userSetupRepository.setUserSetUp(true)
@@ -204,7 +145,7 @@
@Test
fun isExpandToQsEnabled_dozing_false() =
- testComponent.runTest {
+ testScope.runTest {
deviceProvisioningRepository.setDeviceProvisioned(true)
userSetupRepository.setUserSetUp(true)
disableFlagsRepository.disableFlags.value =
@@ -221,7 +162,7 @@
@Test
fun isExpandToQsEnabled_userSetup_true() =
- testComponent.runTest {
+ testScope.runTest {
deviceProvisioningRepository.setDeviceProvisioned(true)
keyguardRepository.setIsDozing(false)
disableFlagsRepository.disableFlags.value =
@@ -238,7 +179,7 @@
@Test
fun isExpandToQsEnabled_notSimpleUserSwitcher_true() =
- testComponent.runTest {
+ testScope.runTest {
deviceProvisioningRepository.setDeviceProvisioned(true)
keyguardRepository.setIsDozing(false)
disableFlagsRepository.disableFlags.value =
@@ -255,7 +196,7 @@
@Test
fun isExpandToQsEnabled_respondsToDozingUpdates() =
- testComponent.runTest {
+ testScope.runTest {
deviceProvisioningRepository.setDeviceProvisioned(true)
keyguardRepository.setIsDozing(false)
disableFlagsRepository.disableFlags.value =
@@ -283,7 +224,7 @@
@Test
fun isExpandToQsEnabled_respondsToDisableUpdates() =
- testComponent.runTest {
+ testScope.runTest {
deviceProvisioningRepository.setDeviceProvisioned(true)
keyguardRepository.setIsDozing(false)
disableFlagsRepository.disableFlags.value =
@@ -315,7 +256,7 @@
@Test
fun isExpandToQsEnabled_respondsToUserUpdates() =
- testComponent.runTest {
+ testScope.runTest {
deviceProvisioningRepository.setDeviceProvisioned(true)
keyguardRepository.setIsDozing(false)
disableFlagsRepository.disableFlags.value =
@@ -344,7 +285,7 @@
@Test
fun fullShadeExpansionWhenShadeLocked() =
- testComponent.runTest {
+ testScope.runTest {
val actual by collectLastValue(underTest.shadeExpansion)
keyguardRepository.setStatusBarState(StatusBarState.SHADE_LOCKED)
@@ -355,7 +296,7 @@
@Test
fun fullShadeExpansionWhenStatusBarStateIsNotShadeLocked() =
- testComponent.runTest {
+ testScope.runTest {
val actual by collectLastValue(underTest.shadeExpansion)
keyguardRepository.setStatusBarState(StatusBarState.KEYGUARD)
@@ -369,7 +310,7 @@
@Test
fun shadeExpansionWhenInSplitShadeAndQsExpanded() =
- testComponent.runTest {
+ testScope.runTest {
val actual by collectLastValue(underTest.shadeExpansion)
// WHEN split shade is enabled and QS is expanded
@@ -386,7 +327,7 @@
@Test
fun shadeExpansionWhenNotInSplitShadeAndQsExpanded() =
- testComponent.runTest {
+ testScope.runTest {
val actual by collectLastValue(underTest.shadeExpansion)
// WHEN split shade is not enabled and QS is expanded
@@ -402,7 +343,7 @@
@Test
fun shadeExpansionWhenNotInSplitShadeAndQsCollapsed() =
- testComponent.runTest {
+ testScope.runTest {
val actual by collectLastValue(underTest.shadeExpansion)
// WHEN split shade is not enabled and QS is expanded
@@ -416,7 +357,7 @@
@Test
fun anyExpansion_shadeGreater() =
- testComponent.runTest() {
+ testScope.runTest() {
// WHEN shade is more expanded than QS
shadeRepository.setLegacyShadeExpansion(.5f)
shadeRepository.setQsExpansion(0f)
@@ -428,7 +369,7 @@
@Test
fun anyExpansion_qsGreater() =
- testComponent.runTest() {
+ testScope.runTest() {
// WHEN qs is more expanded than shade
shadeRepository.setLegacyShadeExpansion(0f)
shadeRepository.setQsExpansion(.5f)
@@ -440,7 +381,7 @@
@Test
fun userInteractingWithShade_shadeDraggedUpAndDown() =
- testComponent.runTest() {
+ testScope.runTest() {
val actual by collectLastValue(underTest.isUserInteractingWithShade)
// GIVEN shade collapsed and not tracking input
shadeRepository.setLegacyShadeExpansion(0f)
@@ -496,7 +437,7 @@
@Test
fun userInteractingWithShade_shadeExpanded() =
- testComponent.runTest() {
+ testScope.runTest() {
val actual by collectLastValue(underTest.isUserInteractingWithShade)
// GIVEN shade collapsed and not tracking input
shadeRepository.setLegacyShadeExpansion(0f)
@@ -531,7 +472,7 @@
@Test
fun userInteractingWithShade_shadePartiallyExpanded() =
- testComponent.runTest() {
+ testScope.runTest() {
val actual by collectLastValue(underTest.isUserInteractingWithShade)
// GIVEN shade collapsed and not tracking input
shadeRepository.setLegacyShadeExpansion(0f)
@@ -572,7 +513,7 @@
@Test
fun userInteractingWithShade_shadeCollapsed() =
- testComponent.runTest() {
+ testScope.runTest() {
val actual by collectLastValue(underTest.isUserInteractingWithShade)
// GIVEN shade expanded and not tracking input
shadeRepository.setLegacyShadeExpansion(1f)
@@ -607,7 +548,7 @@
@Test
fun userInteractingWithQs_qsDraggedUpAndDown() =
- testComponent.runTest() {
+ testScope.runTest() {
val actual by collectLastValue(underTest.isUserInteractingWithQs)
// GIVEN qs collapsed and not tracking input
shadeRepository.setQsExpansion(0f)
@@ -663,7 +604,7 @@
@Test
fun isShadeTouchable_isFalse_whenFrpIsActive() =
- testComponent.runTest {
+ testScope.runTest {
deviceProvisioningRepository.setFactoryResetProtectionActive(true)
keyguardTransitionRepository.sendTransitionStep(
TransitionStep(
@@ -677,7 +618,7 @@
@Test
fun isShadeTouchable_isFalse_whenDeviceAsleepAndNotPulsing() =
- testComponent.runTest {
+ testScope.runTest {
powerRepository.updateWakefulness(
rawState = WakefulnessState.ASLEEP,
lastWakeReason = WakeSleepReason.POWER_BUTTON,
@@ -704,7 +645,7 @@
@Test
fun isShadeTouchable_isTrue_whenDeviceAsleepAndPulsing() =
- testComponent.runTest {
+ testScope.runTest {
powerRepository.updateWakefulness(
rawState = WakefulnessState.ASLEEP,
lastWakeReason = WakeSleepReason.POWER_BUTTON,
@@ -731,7 +672,7 @@
@Test
fun isShadeTouchable_isFalse_whenStartingToSleepAndNotControlScreenOff() =
- testComponent.runTest {
+ testScope.runTest {
powerRepository.updateWakefulness(
rawState = WakefulnessState.STARTING_TO_SLEEP,
lastWakeReason = WakeSleepReason.POWER_BUTTON,
@@ -753,7 +694,7 @@
@Test
fun isShadeTouchable_isTrue_whenStartingToSleepAndControlScreenOff() =
- testComponent.runTest {
+ testScope.runTest {
powerRepository.updateWakefulness(
rawState = WakefulnessState.STARTING_TO_SLEEP,
lastWakeReason = WakeSleepReason.POWER_BUTTON,
@@ -775,7 +716,7 @@
@Test
fun isShadeTouchable_isTrue_whenNotAsleep() =
- testComponent.runTest {
+ testScope.runTest {
powerRepository.updateWakefulness(
rawState = WakefulnessState.AWAKE,
lastWakeReason = WakeSleepReason.POWER_BUTTON,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorLegacyImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorLegacyImplTest.kt
similarity index 74%
rename from packages/SystemUI/tests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorLegacyImplTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorLegacyImplTest.kt
index 6e6e438..682c4ef 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorLegacyImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorLegacyImplTest.kt
@@ -16,108 +16,45 @@
package com.android.systemui.shade.domain.interactor
-import android.content.pm.UserInfo
-import android.os.UserManager
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
-import com.android.systemui.SysUITestComponent
-import com.android.systemui.SysUITestModule
import com.android.systemui.SysuiTestCase
-import com.android.systemui.TestMocksModule
-import com.android.systemui.collectLastValue
-import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository
-import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.flags.FakeFeatureFlagsClassicModule
-import com.android.systemui.flags.Flags
-import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
-import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
+import com.android.systemui.common.ui.data.repository.fakeConfigurationRepository
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
+import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
import com.android.systemui.keyguard.shared.model.StatusBarState
-import com.android.systemui.power.data.repository.FakePowerRepository
+import com.android.systemui.kosmos.testScope
import com.android.systemui.res.R
-import com.android.systemui.runCurrent
-import com.android.systemui.runTest
-import com.android.systemui.scene.domain.interactor.SceneInteractor
-import com.android.systemui.shade.data.repository.FakeShadeRepository
-import com.android.systemui.statusbar.phone.DozeParameters
-import com.android.systemui.user.data.repository.FakeUserRepository
-import com.android.systemui.user.domain.UserDomainLayerModule
-import com.android.systemui.util.mockito.mock
+import com.android.systemui.scene.domain.interactor.sceneInteractor
+import com.android.systemui.shade.data.repository.fakeShadeRepository
+import com.android.systemui.testKosmos
+import com.android.systemui.user.data.repository.fakeUserRepository
import com.google.common.truth.Truth.assertThat
-import dagger.BindsInstance
-import dagger.Component
-import kotlinx.coroutines.runBlocking
-import org.junit.Before
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
import org.junit.Test
+import org.junit.runner.RunWith
+@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
+@RunWith(AndroidJUnit4::class)
class ShadeInteractorLegacyImplTest : SysuiTestCase() {
+ val kosmos = testKosmos()
+ val testScope = kosmos.testScope
+ val configurationRepository = kosmos.fakeConfigurationRepository
+ val keyguardRepository = kosmos.fakeKeyguardRepository
+ val keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository
+ val sceneInteractor = kosmos.sceneInteractor
+ val shadeRepository = kosmos.fakeShadeRepository
+ val userRepository = kosmos.fakeUserRepository
- @SysUISingleton
- @Component(
- modules =
- [
- SysUITestModule::class,
- UserDomainLayerModule::class,
- ]
- )
- interface TestComponent : SysUITestComponent<ShadeInteractorLegacyImpl> {
-
- val configurationRepository: FakeConfigurationRepository
- val keyguardRepository: FakeKeyguardRepository
- val keyguardTransitionRepository: FakeKeyguardTransitionRepository
- val powerRepository: FakePowerRepository
- val sceneInteractor: SceneInteractor
- val shadeRepository: FakeShadeRepository
- val userRepository: FakeUserRepository
-
- @Component.Factory
- interface Factory {
- fun create(
- @BindsInstance test: SysuiTestCase,
- featureFlags: FakeFeatureFlagsClassicModule,
- mocks: TestMocksModule,
- ): TestComponent
- }
- }
-
- private val dozeParameters: DozeParameters = mock()
-
- private val testComponent: TestComponent =
- DaggerShadeInteractorLegacyImplTest_TestComponent.factory()
- .create(
- test = this,
- featureFlags =
- FakeFeatureFlagsClassicModule { set(Flags.FULL_SCREEN_USER_SWITCHER, true) },
- mocks =
- TestMocksModule(
- dozeParameters = dozeParameters,
- ),
- )
-
- @Before
- fun setUp() {
- runBlocking {
- val userInfos =
- listOf(
- UserInfo(
- /* id= */ 0,
- /* name= */ "zero",
- /* iconPath= */ "",
- /* flags= */ UserInfo.FLAG_PRIMARY or
- UserInfo.FLAG_ADMIN or
- UserInfo.FLAG_FULL,
- UserManager.USER_TYPE_FULL_SYSTEM,
- ),
- )
- testComponent.apply {
- userRepository.setUserInfos(userInfos)
- userRepository.setSelectedUserInfo(userInfos[0])
- }
- }
- }
+ val underTest = kosmos.shadeInteractorLegacyImpl
@Test
fun fullShadeExpansionWhenShadeLocked() =
- testComponent.runTest() {
+ testScope.runTest {
val actual by collectLastValue(underTest.shadeExpansion)
keyguardRepository.setStatusBarState(StatusBarState.SHADE_LOCKED)
@@ -128,7 +65,7 @@
@Test
fun fullShadeExpansionWhenStatusBarStateIsNotShadeLocked() =
- testComponent.runTest() {
+ testScope.runTest {
val actual by collectLastValue(underTest.shadeExpansion)
keyguardRepository.setStatusBarState(StatusBarState.KEYGUARD)
@@ -142,7 +79,7 @@
@Test
fun shadeExpansionWhenInSplitShadeAndQsExpanded() =
- testComponent.runTest() {
+ testScope.runTest {
val actual by collectLastValue(underTest.shadeExpansion)
// WHEN split shade is enabled and QS is expanded
@@ -159,7 +96,7 @@
@Test
fun shadeExpansionWhenNotInSplitShadeAndQsExpanded() =
- testComponent.runTest() {
+ testScope.runTest {
val actual by collectLastValue(underTest.shadeExpansion)
// WHEN split shade is not enabled and QS is expanded
@@ -175,7 +112,7 @@
@Test
fun shadeExpansionWhenNotInSplitShadeAndQsCollapsed() =
- testComponent.runTest() {
+ testScope.runTest {
val actual by collectLastValue(underTest.shadeExpansion)
// WHEN split shade is not enabled and QS is expanded
@@ -189,7 +126,7 @@
@Test
fun userInteractingWithShade_shadeDraggedUpAndDown() =
- testComponent.runTest() {
+ testScope.runTest {
val actual by collectLastValue(underTest.isUserInteractingWithShade)
// GIVEN shade collapsed and not tracking input
shadeRepository.setLegacyShadeExpansion(0f)
@@ -245,7 +182,7 @@
@Test
fun userInteractingWithShade_shadeExpanded() =
- testComponent.runTest() {
+ testScope.runTest {
val actual by collectLastValue(underTest.isUserInteractingWithShade)
// GIVEN shade collapsed and not tracking input
shadeRepository.setLegacyShadeExpansion(0f)
@@ -280,7 +217,7 @@
@Test
fun userInteractingWithShade_shadePartiallyExpanded() =
- testComponent.runTest() {
+ testScope.runTest {
val actual by collectLastValue(underTest.isUserInteractingWithShade)
// GIVEN shade collapsed and not tracking input
shadeRepository.setLegacyShadeExpansion(0f)
@@ -321,7 +258,7 @@
@Test
fun userInteractingWithShade_shadeCollapsed() =
- testComponent.runTest() {
+ testScope.runTest {
val actual by collectLastValue(underTest.isUserInteractingWithShade)
// GIVEN shade expanded and not tracking input
shadeRepository.setLegacyShadeExpansion(1f)
@@ -356,7 +293,7 @@
@Test
fun userInteractingWithQs_qsDraggedUpAndDown() =
- testComponent.runTest() {
+ testScope.runTest {
val actual by collectLastValue(underTest.isUserInteractingWithQs)
// GIVEN qs collapsed and not tracking input
shadeRepository.setQsExpansion(0f)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImplTest.kt
similarity index 83%
rename from packages/SystemUI/tests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImplTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImplTest.kt
index 310b86f..bf136cd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImplTest.kt
@@ -16,114 +16,48 @@
package com.android.systemui.shade.domain.interactor
-import android.content.pm.UserInfo
-import android.os.UserManager
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
-import com.android.systemui.SysUITestComponent
-import com.android.systemui.SysUITestModule
import com.android.systemui.SysuiTestCase
-import com.android.systemui.TestMocksModule
-import com.android.systemui.collectLastValue
-import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository
-import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.flags.FakeFeatureFlagsClassicModule
-import com.android.systemui.flags.Flags
-import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
-import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
+import com.android.systemui.common.ui.data.repository.fakeConfigurationRepository
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
+import com.android.systemui.keyguard.data.repository.keyguardTransitionRepository
import com.android.systemui.keyguard.shared.model.StatusBarState
-import com.android.systemui.power.data.repository.FakePowerRepository
+import com.android.systemui.kosmos.testScope
import com.android.systemui.res.R
-import com.android.systemui.runCurrent
-import com.android.systemui.runTest
-import com.android.systemui.scene.domain.interactor.SceneInteractor
+import com.android.systemui.scene.domain.interactor.sceneInteractor
import com.android.systemui.scene.shared.model.ObservableTransitionState
import com.android.systemui.scene.shared.model.SceneKey
-import com.android.systemui.shade.data.repository.FakeShadeRepository
-import com.android.systemui.statusbar.phone.DozeParameters
-import com.android.systemui.user.data.repository.FakeUserRepository
-import com.android.systemui.user.domain.UserDomainLayerModule
-import com.android.systemui.util.mockito.mock
+import com.android.systemui.testKosmos
+import com.android.systemui.user.data.repository.userRepository
import com.google.common.truth.Truth
-import dagger.BindsInstance
-import dagger.Component
+import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.flowOf
-import kotlinx.coroutines.runBlocking
-import org.junit.Before
-import org.junit.Ignore
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
import org.junit.Test
+import org.junit.runner.RunWith
+@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
+@RunWith(AndroidJUnit4::class)
class ShadeInteractorSceneContainerImplTest : SysuiTestCase() {
- @SysUISingleton
- @Component(
- modules =
- [
- SysUITestModule::class,
- UserDomainLayerModule::class,
- ]
- )
- interface TestComponent : SysUITestComponent<ShadeInteractorSceneContainerImpl> {
+ val kosmos = testKosmos()
+ val testComponent = kosmos.testScope
+ val configurationRepository = kosmos.fakeConfigurationRepository
+ val keyguardRepository = kosmos.fakeKeyguardRepository
+ val keyguardTransitionRepository = kosmos.keyguardTransitionRepository
+ val sceneInteractor = kosmos.sceneInteractor
+ val userRepository = kosmos.userRepository
- val configurationRepository: FakeConfigurationRepository
- val keyguardRepository: FakeKeyguardRepository
- val keyguardTransitionRepository: FakeKeyguardTransitionRepository
- val powerRepository: FakePowerRepository
- val sceneInteractor: SceneInteractor
- val shadeRepository: FakeShadeRepository
- val userRepository: FakeUserRepository
+ val underTest = kosmos.shadeInteractorSceneContainerImpl
- @Component.Factory
- interface Factory {
- fun create(
- @BindsInstance test: SysuiTestCase,
- featureFlags: FakeFeatureFlagsClassicModule,
- mocks: TestMocksModule,
- ): TestComponent
- }
- }
-
- private val dozeParameters: DozeParameters = mock()
-
- private val testComponent: TestComponent =
- DaggerShadeInteractorSceneContainerImplTest_TestComponent.factory()
- .create(
- test = this,
- featureFlags =
- FakeFeatureFlagsClassicModule { set(Flags.FULL_SCREEN_USER_SWITCHER, true) },
- mocks =
- TestMocksModule(
- dozeParameters = dozeParameters,
- ),
- )
-
- @Before
- fun setUp() {
- runBlocking {
- val userInfos =
- listOf(
- UserInfo(
- /* id= */ 0,
- /* name= */ "zero",
- /* iconPath= */ "",
- /* flags= */ UserInfo.FLAG_PRIMARY or
- UserInfo.FLAG_ADMIN or
- UserInfo.FLAG_FULL,
- UserManager.USER_TYPE_FULL_SYSTEM,
- ),
- )
- testComponent.apply {
- userRepository.setUserInfos(userInfos)
- userRepository.setSelectedUserInfo(userInfos[0])
- }
- }
- }
-
- @Ignore("b/309825977")
@Test
fun qsExpansionWhenInSplitShadeAndQsExpanded() =
- testComponent.runTest() {
+ testComponent.runTest {
val actual by collectLastValue(underTest.qsExpansion)
// WHEN split shade is enabled and QS is expanded
@@ -148,10 +82,9 @@
Truth.assertThat(actual).isEqualTo(.3f)
}
- @Ignore("b/309825977")
@Test
fun qsExpansionWhenNotInSplitShadeAndQsExpanded() =
- testComponent.runTest() {
+ testComponent.runTest {
val actual by collectLastValue(underTest.qsExpansion)
// WHEN split shade is not enabled and QS is expanded
@@ -179,7 +112,7 @@
@Test
fun qsFullscreen_falseWhenTransitioning() =
- testComponent.runTest() {
+ testComponent.runTest {
val actual by collectLastValue(underTest.isQsFullscreen)
// WHEN scene transition active
@@ -203,7 +136,7 @@
@Test
fun qsFullscreen_falseWhenIdleNotQS() =
- testComponent.runTest() {
+ testComponent.runTest {
val actual by collectLastValue(underTest.isQsFullscreen)
// WHEN Idle but not on QuickSettings scene
@@ -221,7 +154,7 @@
@Test
fun qsFullscreen_trueWhenIdleQS() =
- testComponent.runTest() {
+ testComponent.runTest {
val actual by collectLastValue(underTest.isQsFullscreen)
// WHEN Idle on QuickSettings scene
@@ -239,7 +172,7 @@
@Test
fun lockscreenShadeExpansion_idle_onScene() =
- testComponent.runTest() {
+ testComponent.runTest {
// GIVEN an expansion flow based on transitions to and from a scene
val key = SceneKey.Shade
val expansion = underTest.sceneBasedExpansion(sceneInteractor, key)
@@ -256,7 +189,7 @@
@Test
fun lockscreenShadeExpansion_idle_onDifferentScene() =
- testComponent.runTest() {
+ testComponent.runTest {
// GIVEN an expansion flow based on transitions to and from a scene
val expansion = underTest.sceneBasedExpansion(sceneInteractor, SceneKey.Shade)
val expansionAmount by collectLastValue(expansion)
@@ -274,7 +207,7 @@
@Test
fun lockscreenShadeExpansion_transitioning_toScene() =
- testComponent.runTest() {
+ testComponent.runTest {
// GIVEN an expansion flow based on transitions to and from a scene
val key = SceneKey.QuickSettings
val expansion = underTest.sceneBasedExpansion(sceneInteractor, key)
@@ -312,7 +245,7 @@
@Test
fun lockscreenShadeExpansion_transitioning_fromScene() =
- testComponent.runTest() {
+ testComponent.runTest {
// GIVEN an expansion flow based on transitions to and from a scene
val key = SceneKey.QuickSettings
val expansion = underTest.sceneBasedExpansion(sceneInteractor, key)
@@ -349,7 +282,7 @@
}
fun isQsBypassingShade_goneToQs() =
- testComponent.runTest() {
+ testComponent.runTest {
val actual by collectLastValue(underTest.isQsBypassingShade)
// WHEN transitioning from QS directly to Gone
@@ -372,7 +305,7 @@
}
fun isQsBypassingShade_shadeToQs() =
- testComponent.runTest() {
+ testComponent.runTest {
val actual by collectLastValue(underTest.isQsBypassingShade)
// WHEN transitioning from QS to Shade
@@ -396,7 +329,7 @@
@Test
fun lockscreenShadeExpansion_transitioning_toAndFromDifferentScenes() =
- testComponent.runTest() {
+ testComponent.runTest {
// GIVEN an expansion flow based on transitions to and from a scene
val expansion = underTest.sceneBasedExpansion(sceneInteractor, SceneKey.QuickSettings)
val expansionAmount by collectLastValue(expansion)
@@ -433,7 +366,7 @@
@Test
fun userInteracting_idle() =
- testComponent.runTest() {
+ testComponent.runTest {
// GIVEN an interacting flow based on transitions to and from a scene
val key = SceneKey.Shade
val interactingFlow = underTest.sceneBasedInteracting(sceneInteractor, key)
@@ -450,7 +383,7 @@
@Test
fun userInteracting_transitioning_toScene_programmatic() =
- testComponent.runTest() {
+ testComponent.runTest {
// GIVEN an interacting flow based on transitions to and from a scene
val key = SceneKey.QuickSettings
val interactingFlow = underTest.sceneBasedInteracting(sceneInteractor, key)
@@ -488,7 +421,7 @@
@Test
fun userInteracting_transitioning_toScene_userInputDriven() =
- testComponent.runTest() {
+ testComponent.runTest {
// GIVEN an interacting flow based on transitions to and from a scene
val key = SceneKey.QuickSettings
val interactingFlow = underTest.sceneBasedInteracting(sceneInteractor, key)
@@ -526,7 +459,7 @@
@Test
fun userInteracting_transitioning_fromScene_programmatic() =
- testComponent.runTest() {
+ testComponent.runTest {
// GIVEN an interacting flow based on transitions to and from a scene
val key = SceneKey.QuickSettings
val interactingFlow = underTest.sceneBasedInteracting(sceneInteractor, key)
@@ -564,7 +497,7 @@
@Test
fun userInteracting_transitioning_fromScene_userInputDriven() =
- testComponent.runTest() {
+ testComponent.runTest {
// GIVEN an interacting flow based on transitions to and from a scene
val key = SceneKey.QuickSettings
val interactingFlow = underTest.sceneBasedInteracting(sceneInteractor, key)
@@ -602,7 +535,7 @@
@Test
fun userInteracting_transitioning_toAndFromDifferentScenes() =
- testComponent.runTest() {
+ testComponent.runTest {
// GIVEN an interacting flow based on transitions to and from a scene
val interactingFlow = underTest.sceneBasedInteracting(sceneInteractor, SceneKey.Shade)
val interacting by collectLastValue(interactingFlow)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModelTest.kt
index e9a2a3b..c0aaab3 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModelTest.kt
@@ -9,8 +9,6 @@
import com.android.systemui.flags.Flags
import com.android.systemui.kosmos.testScope
import com.android.systemui.scene.domain.interactor.sceneInteractor
-import com.android.systemui.scene.shared.model.ObservableTransitionState
-import com.android.systemui.scene.shared.model.SceneKey
import com.android.systemui.statusbar.pipeline.airplane.data.repository.FakeAirplaneModeRepository
import com.android.systemui.statusbar.pipeline.airplane.domain.interactor.AirplaneModeInteractor
import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
@@ -22,8 +20,6 @@
import com.android.systemui.testKosmos
import com.android.systemui.util.mockito.mock
import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
@@ -74,74 +70,6 @@
}
@Test
- fun isTransitioning_idle_false() =
- testScope.runTest {
- val isTransitioning by collectLastValue(underTest.isTransitioning)
- sceneInteractor.setTransitionState(
- MutableStateFlow(ObservableTransitionState.Idle(SceneKey.Shade))
- )
-
- assertThat(isTransitioning).isFalse()
- }
-
- @Test
- fun isTransitioning_shadeToQs_true() =
- testScope.runTest {
- val isTransitioning by collectLastValue(underTest.isTransitioning)
- sceneInteractor.setTransitionState(
- MutableStateFlow(
- ObservableTransitionState.Transition(
- fromScene = SceneKey.Shade,
- toScene = SceneKey.QuickSettings,
- progress = MutableStateFlow(0.5f),
- isInitiatedByUserInput = false,
- isUserInputOngoing = flowOf(false),
- )
- )
- )
-
- assertThat(isTransitioning).isTrue()
- }
-
- @Test
- fun isTransitioning_qsToShade_true() =
- testScope.runTest {
- val isTransitioning by collectLastValue(underTest.isTransitioning)
- sceneInteractor.setTransitionState(
- MutableStateFlow(
- ObservableTransitionState.Transition(
- fromScene = SceneKey.QuickSettings,
- toScene = SceneKey.Shade,
- progress = MutableStateFlow(0.5f),
- isInitiatedByUserInput = false,
- isUserInputOngoing = flowOf(false),
- )
- )
- )
-
- assertThat(isTransitioning).isTrue()
- }
-
- @Test
- fun isTransitioning_otherTransition_false() =
- testScope.runTest {
- val isTransitioning by collectLastValue(underTest.isTransitioning)
- sceneInteractor.setTransitionState(
- MutableStateFlow(
- ObservableTransitionState.Transition(
- fromScene = SceneKey.Gone,
- toScene = SceneKey.Shade,
- progress = MutableStateFlow(0.5f),
- isInitiatedByUserInput = false,
- isUserInputOngoing = flowOf(false),
- )
- )
- )
-
- assertThat(isTransitioning).isFalse()
- }
-
- @Test
fun mobileSubIds_update() =
testScope.runTest {
val mobileSubIds by collectLastValue(underTest.mobileSubIds)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/SystemUIDialogTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/SystemUIDialogTest.java
index 7274c0c..4528957 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/SystemUIDialogTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/SystemUIDialogTest.java
@@ -31,6 +31,7 @@
import android.platform.test.annotations.RequiresFlagsEnabled;
import android.platform.test.flag.junit.CheckFlagsRule;
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
+import android.platform.test.ravenwood.RavenwoodRule;
import android.testing.TestableLooper.RunWithLooper;
import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -66,8 +67,11 @@
@Mock
private SystemUIDialog.Delegate mDelegate;
+ // TODO(b/292141694): build out Ravenwood support for DeviceFlagsValueProvider
+ // Ravenwood already has solid support for SetFlagsRule, but CheckFlagsRule will be added soon
@Rule
- public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
+ public final CheckFlagsRule mCheckFlagsRule = RavenwoodRule.isOnRavenwood() ? null
+ : DeviceFlagsValueProvider.createCheckFlagsRule();
@Before
public void setup() {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/bottombar/ui/viewmodel/BottomBarViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/bottombar/ui/viewmodel/BottomBarViewModelTest.kt
new file mode 100644
index 0000000..471c8d8
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/bottombar/ui/viewmodel/BottomBarViewModelTest.kt
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.volume.panel.component.bottombar.ui.viewmodel
+
+import android.content.Intent
+import android.provider.Settings
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.plugins.activityStarter
+import com.android.systemui.testKosmos
+import com.android.systemui.util.mockito.capture
+import com.android.systemui.util.mockito.eq
+import com.android.systemui.volume.panel.volumePanelViewModel
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
+import org.mockito.Captor
+import org.mockito.Mockito.verify
+import org.mockito.junit.MockitoJUnit
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class BottomBarViewModelTest : SysuiTestCase() {
+
+ @JvmField @Rule var mockitoRule = MockitoJUnit.rule()
+
+ @Captor private lateinit var intentCaptor: ArgumentCaptor<Intent>
+
+ private val kosmos = testKosmos()
+
+ private lateinit var underTest: BottomBarViewModel
+
+ private fun initUnderTest() {
+ underTest = with(kosmos) { BottomBarViewModel(activityStarter, volumePanelViewModel) }
+ }
+
+ @Test
+ fun onDoneClicked_hidesPanel() {
+ with(kosmos) {
+ testScope.runTest {
+ initUnderTest()
+ underTest.onDoneClicked()
+ runCurrent()
+
+ val volumePanelState by collectLastValue(volumePanelViewModel.volumePanelState)
+ assertThat(volumePanelState!!.isVisible).isFalse()
+ }
+ }
+ }
+
+ @Test
+ fun onSettingsClicked_dismissesPanelAndNavigatesToSettings() {
+ with(kosmos) {
+ testScope.runTest {
+ initUnderTest()
+ underTest.onSettingsClicked()
+
+ runCurrent()
+
+ val volumePanelState by collectLastValue(volumePanelViewModel.volumePanelState)
+ assertThat(volumePanelState!!.isVisible).isFalse()
+ verify(activityStarter).startActivity(capture(intentCaptor), eq(true))
+ assertThat(intentCaptor.value.action).isEqualTo(Settings.ACTION_SOUND_SETTINGS)
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/domain/interactor/ComponentsInteractorImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/domain/interactor/ComponentsInteractorImplTest.kt
new file mode 100644
index 0000000..6256eec
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/domain/interactor/ComponentsInteractorImplTest.kt
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.volume.panel.domain.interactor
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.volume.panel.availableCriteria
+import com.android.systemui.volume.panel.criteriaByKey
+import com.android.systemui.volume.panel.defaultCriteria
+import com.android.systemui.volume.panel.domain.model.ComponentModel
+import com.android.systemui.volume.panel.enabledComponents
+import com.android.systemui.volume.panel.shared.model.VolumePanelComponentKey
+import com.android.systemui.volume.panel.unavailableCriteria
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class ComponentsInteractorImplTest : SysuiTestCase() {
+
+ private val kosmos = Kosmos()
+
+ private lateinit var underTest: ComponentsInteractor
+
+ private fun initUnderTest() {
+ underTest =
+ with(kosmos) {
+ ComponentsInteractorImpl(
+ enabledComponents,
+ defaultCriteria,
+ testScope.backgroundScope,
+ criteriaByKey,
+ )
+ }
+ }
+
+ @Test
+ fun componentsAvailability_checked() {
+ with(kosmos) {
+ testScope.runTest {
+ enabledComponents =
+ setOf(
+ BOTTOM_BAR,
+ COMPONENT_1,
+ COMPONENT_2,
+ )
+ criteriaByKey =
+ mapOf(
+ BOTTOM_BAR to availableCriteria,
+ COMPONENT_1 to unavailableCriteria,
+ COMPONENT_2 to availableCriteria,
+ )
+ initUnderTest()
+
+ val components by collectLastValue(underTest.components)
+
+ assertThat(components)
+ .containsExactly(
+ ComponentModel(BOTTOM_BAR, true),
+ ComponentModel(COMPONENT_1, false),
+ ComponentModel(COMPONENT_2, true),
+ )
+ }
+ }
+ }
+
+ @Test
+ fun noCriteria_fallbackToDefaultCriteria() {
+ with(kosmos) {
+ testScope.runTest {
+ enabledComponents =
+ setOf(
+ BOTTOM_BAR,
+ COMPONENT_1,
+ COMPONENT_2,
+ )
+ criteriaByKey =
+ mapOf(
+ BOTTOM_BAR to availableCriteria,
+ COMPONENT_2 to availableCriteria,
+ )
+ defaultCriteria = unavailableCriteria
+ initUnderTest()
+
+ val components by collectLastValue(underTest.components)
+
+ assertThat(components)
+ .containsExactly(
+ ComponentModel(BOTTOM_BAR, true),
+ ComponentModel(COMPONENT_1, false),
+ ComponentModel(COMPONENT_2, true),
+ )
+ }
+ }
+ }
+
+ private companion object {
+ const val BOTTOM_BAR: VolumePanelComponentKey = "test_bottom_bar"
+ const val COMPONENT_1: VolumePanelComponentKey = "test_component:1"
+ const val COMPONENT_2: VolumePanelComponentKey = "test_component:2"
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/domain/interactor/ComponentsInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/domain/interactor/ComponentsInteractorTest.kt
deleted file mode 100644
index dbff63f..0000000
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/domain/interactor/ComponentsInteractorTest.kt
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.volume.panel.domain.interactor
-
-class ComponentsInteractorTest {
-
- // TODO(b/318080198) Write tests
-}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/ui/composable/ComponentsFactoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/ui/composable/ComponentsFactoryTest.kt
new file mode 100644
index 0000000..3dbf23e
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/ui/composable/ComponentsFactoryTest.kt
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.volume.panel.ui.composable
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.testKosmos
+import com.android.systemui.volume.panel.componentByKey
+import com.android.systemui.volume.panel.mockVolumePanelUiComponentProvider
+import com.android.systemui.volume.panel.shared.model.VolumePanelComponentKey
+import com.google.common.truth.Truth
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class ComponentsFactoryTest : SysuiTestCase() {
+
+ private val kosmos = testKosmos()
+
+ private lateinit var underTest: ComponentsFactory
+
+ private fun initUnderTest() {
+ underTest = ComponentsFactory(kosmos.componentByKey)
+ }
+
+ @Test
+ fun existingComponent_created() {
+ kosmos.componentByKey = mapOf(TEST_COMPONENT to kosmos.mockVolumePanelUiComponentProvider)
+ initUnderTest()
+
+ val component = underTest.createComponent(TEST_COMPONENT)
+
+ Truth.assertThat(component).isNotNull()
+ }
+
+ @Test(expected = IllegalArgumentException::class)
+ fun componentAbsence_throws() {
+ kosmos.componentByKey = emptyMap()
+ initUnderTest()
+
+ underTest.createComponent(TEST_COMPONENT)
+ }
+
+ private companion object {
+ const val TEST_COMPONENT: VolumePanelComponentKey = "test_component"
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/ui/viewmodel/DefaultComponentsLayoutManagerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/ui/viewmodel/DefaultComponentsLayoutManagerTest.kt
index e5fb942..35d9698 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/ui/viewmodel/DefaultComponentsLayoutManagerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/ui/viewmodel/DefaultComponentsLayoutManagerTest.kt
@@ -16,7 +16,78 @@
package com.android.systemui.volume.panel.ui.viewmodel
-class DefaultComponentsLayoutManagerTest {
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.testKosmos
+import com.android.systemui.volume.panel.mockVolumePanelUiComponent
+import com.android.systemui.volume.panel.shared.model.VolumePanelComponentKey
+import com.android.systemui.volume.panel.ui.layout.ComponentsLayoutManager
+import com.android.systemui.volume.panel.ui.layout.DefaultComponentsLayoutManager
+import com.google.common.truth.Truth
+import org.junit.Test
+import org.junit.runner.RunWith
- // TODO(b/318080198) Write tests
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class DefaultComponentsLayoutManagerTest : SysuiTestCase() {
+
+ private val kosmos = testKosmos()
+ private val underTest: ComponentsLayoutManager = DefaultComponentsLayoutManager()
+
+ @Test
+ fun bottomBar_isSet() {
+ val bottomBarComponentState =
+ ComponentState(BOTTOM_BAR, kosmos.mockVolumePanelUiComponent, false)
+ val layout =
+ underTest.layout(
+ VolumePanelState(0, false),
+ setOf(
+ bottomBarComponentState,
+ ComponentState(COMPONENT_1, kosmos.mockVolumePanelUiComponent, false),
+ ComponentState(COMPONENT_2, kosmos.mockVolumePanelUiComponent, false),
+ )
+ )
+
+ Truth.assertThat(layout.bottomBarComponent).isEqualTo(bottomBarComponentState)
+ }
+
+ @Test
+ fun componentsAreInOrder() {
+ val bottomBarComponentState =
+ ComponentState(BOTTOM_BAR, kosmos.mockVolumePanelUiComponent, false)
+ val component1State = ComponentState(COMPONENT_1, kosmos.mockVolumePanelUiComponent, false)
+ val component2State = ComponentState(COMPONENT_2, kosmos.mockVolumePanelUiComponent, false)
+ val layout =
+ underTest.layout(
+ VolumePanelState(0, false),
+ setOf(
+ bottomBarComponentState,
+ component1State,
+ component2State,
+ )
+ )
+
+ Truth.assertThat(layout.contentComponents[0]).isEqualTo(component1State)
+ Truth.assertThat(layout.contentComponents[1]).isEqualTo(component2State)
+ }
+
+ @Test(expected = IllegalStateException::class)
+ fun bottomBarAbsence_throwsException() {
+ val component1State = ComponentState(COMPONENT_1, kosmos.mockVolumePanelUiComponent, false)
+ val component2State = ComponentState(COMPONENT_2, kosmos.mockVolumePanelUiComponent, false)
+ underTest.layout(
+ VolumePanelState(0, false),
+ setOf(
+ component1State,
+ component2State,
+ )
+ )
+ }
+
+ private companion object {
+ const val BOTTOM_BAR: VolumePanelComponentKey = "bottom_bar"
+ const val COMPONENT_1: VolumePanelComponentKey = "test_component:1"
+ const val COMPONENT_2: VolumePanelComponentKey = "test_component:2"
+ }
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/ui/viewmodel/VolumePanelViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/ui/viewmodel/VolumePanelViewModelTest.kt
index 9795237..c4c9cc6 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/ui/viewmodel/VolumePanelViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/ui/viewmodel/VolumePanelViewModelTest.kt
@@ -16,7 +16,120 @@
package com.android.systemui.volume.panel.ui.viewmodel
-class VolumePanelViewModelTest {
+import android.content.res.Configuration
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.statusbar.policy.fakeConfigurationController
+import com.android.systemui.testKosmos
+import com.android.systemui.volume.panel.componentByKey
+import com.android.systemui.volume.panel.componentsLayoutManager
+import com.android.systemui.volume.panel.criteriaByKey
+import com.android.systemui.volume.panel.dagger.factory.KosmosVolumePanelComponentFactory
+import com.android.systemui.volume.panel.mockVolumePanelUiComponentProvider
+import com.android.systemui.volume.panel.shared.model.VolumePanelComponentKey
+import com.android.systemui.volume.panel.ui.layout.FakeComponentsLayoutManager
+import com.android.systemui.volume.panel.unavailableCriteria
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
- // TODO(b/318080198) Write tests
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+@OptIn(ExperimentalCoroutinesApi::class)
+class VolumePanelViewModelTest : SysuiTestCase() {
+
+ private val kosmos =
+ testKosmos().apply {
+ componentsLayoutManager = FakeComponentsLayoutManager { it.key == BOTTOM_BAR }
+ }
+
+ private val testableResources = context.orCreateTestableResources
+
+ private lateinit var underTest: VolumePanelViewModel
+
+ private fun initUnderTest() {
+ underTest =
+ VolumePanelViewModel(
+ testableResources.resources,
+ KosmosVolumePanelComponentFactory(kosmos),
+ kosmos.fakeConfigurationController,
+ )
+ }
+
+ @Test
+ fun dismissingPanel_changesVisibility() {
+ with(kosmos) {
+ testScope.runTest {
+ initUnderTest()
+ assertThat(underTest.volumePanelState.value.isVisible).isTrue()
+
+ underTest.dismissPanel()
+ runCurrent()
+
+ assertThat(underTest.volumePanelState.value.isVisible).isFalse()
+ }
+ }
+ }
+
+ @Test
+ fun orientationChanges_panelOrientationChanges() {
+ with(kosmos) {
+ testScope.runTest {
+ initUnderTest()
+ val volumePanelState by collectLastValue(underTest.volumePanelState)
+ testableResources.overrideConfiguration(
+ Configuration().apply { orientation = Configuration.ORIENTATION_PORTRAIT }
+ )
+ assertThat(volumePanelState!!.orientation)
+ .isEqualTo(Configuration.ORIENTATION_PORTRAIT)
+
+ fakeConfigurationController.onConfigurationChanged(
+ Configuration().apply { orientation = Configuration.ORIENTATION_LANDSCAPE }
+ )
+ runCurrent()
+
+ assertThat(volumePanelState!!.orientation)
+ .isEqualTo(Configuration.ORIENTATION_LANDSCAPE)
+ }
+ }
+ }
+
+ @Test
+ fun components_areReturned() {
+ with(kosmos) {
+ testScope.runTest {
+ componentByKey =
+ mapOf(
+ COMPONENT_1 to mockVolumePanelUiComponentProvider,
+ COMPONENT_2 to mockVolumePanelUiComponentProvider,
+ BOTTOM_BAR to mockVolumePanelUiComponentProvider,
+ )
+ criteriaByKey = mapOf(COMPONENT_2 to unavailableCriteria)
+ initUnderTest()
+
+ val componentsLayout by collectLastValue(underTest.componentsLayout)
+ runCurrent()
+
+ assertThat(componentsLayout!!.contentComponents).hasSize(2)
+ assertThat(componentsLayout!!.contentComponents[0].key).isEqualTo(COMPONENT_1)
+ assertThat(componentsLayout!!.contentComponents[0].isVisible).isTrue()
+ assertThat(componentsLayout!!.contentComponents[1].key).isEqualTo(COMPONENT_2)
+ assertThat(componentsLayout!!.contentComponents[1].isVisible).isFalse()
+ assertThat(componentsLayout!!.bottomBarComponent.key).isEqualTo(BOTTOM_BAR)
+ assertThat(componentsLayout!!.bottomBarComponent.isVisible).isTrue()
+ }
+ }
+ }
+
+ private companion object {
+ const val BOTTOM_BAR: VolumePanelComponentKey = "test_bottom_bar"
+ const val COMPONENT_1: VolumePanelComponentKey = "test_component:1"
+ const val COMPONENT_2: VolumePanelComponentKey = "test_component:2"
+ }
}
diff --git a/packages/SystemUI/res-keyguard/values-af/strings.xml b/packages/SystemUI/res-keyguard/values-af/strings.xml
index f801990..3b2eb15 100644
--- a/packages/SystemUI/res-keyguard/values-af/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-af/strings.xml
@@ -33,10 +33,8 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Laai tans"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Laai tans vinnig"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Laai tans stadig"</string>
- <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
- <skip />
- <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
- <skip />
+ <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Laaiproses is onderbreek om battery te beskerm"</string>
+ <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Gaan die laaibykomstigheid na"</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"Netwerk is gesluit"</string>
<string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Geen SIM nie"</string>
<string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"Onbruikbare SIM."</string>
diff --git a/packages/SystemUI/res-keyguard/values-am/strings.xml b/packages/SystemUI/res-keyguard/values-am/strings.xml
index 356eebb..c3d141c 100644
--- a/packages/SystemUI/res-keyguard/values-am/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-am/strings.xml
@@ -33,10 +33,8 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ኃይል በመሙላት ላይ"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • በፍጥነት ኃይልን በመሙላት ላይ"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • በዝግታ ኃይልን በመሙላት ላይ"</string>
- <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
- <skip />
- <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
- <skip />
+ <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> - ባትሪን ለመጠበቅ ኃይል መሙላት በይቆይ ላይ"</string>
+ <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • የኃይል መሙላት መለዋወጫን ይፈትሹ"</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"አውታረ መረብ ተቆልፏል"</string>
<string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"ምንም SIM የለም"</string>
<string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"ጥቅም ላይ የማይውል ሲም።"</string>
diff --git a/packages/SystemUI/res-keyguard/values-ar/strings.xml b/packages/SystemUI/res-keyguard/values-ar/strings.xml
index 707388e..cf8341d 100644
--- a/packages/SystemUI/res-keyguard/values-ar/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ar/strings.xml
@@ -33,10 +33,8 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • جارٍ الشحن"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • جارٍ الشحن سريعًا"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • جارٍ الشحن ببطء"</string>
- <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
- <skip />
- <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
- <skip />
+ <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • الشحن معلّق لحماية البطارية"</string>
+ <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • يُرجى فحص ملحق الشحن."</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"الشبكة مؤمّنة"</string>
<string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"لا تتوفر شريحة SIM."</string>
<string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"شريحة SIM غير قابلة للاستخدام."</string>
diff --git a/packages/SystemUI/res-keyguard/values-as/strings.xml b/packages/SystemUI/res-keyguard/values-as/strings.xml
index 8b9d306..d11a9c1 100644
--- a/packages/SystemUI/res-keyguard/values-as/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-as/strings.xml
@@ -33,10 +33,8 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • চ্চার্জ কৰি থকা হৈছে"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • দ্ৰুত গতিৰে চাৰ্জ কৰি থকা হৈছে"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • লাহে লাহে চাৰ্জ কৰি থকা হৈছে"</string>
- <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
- <skip />
- <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
- <skip />
+ <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • বেটাৰী সুৰক্ষিত কৰিবলৈ চাৰ্জিং স্থগিত ৰখা হৈছে"</string>
+ <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • চাৰ্জিঙৰ সৈতে জড়িত আনুষংগিক সামগ্ৰী পৰীক্ষা কৰক"</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"নেটৱর্ক লক কৰা অৱস্থাত আছে"</string>
<string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"কোনো ছিম নাই"</string>
<string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"ব্যৱহাৰ কৰিব নোৱৰা ছিম।"</string>
diff --git a/packages/SystemUI/res-keyguard/values-az/strings.xml b/packages/SystemUI/res-keyguard/values-az/strings.xml
index 39d8032..4de32d9 100644
--- a/packages/SystemUI/res-keyguard/values-az/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-az/strings.xml
@@ -33,10 +33,8 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Enerji yığır"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Sürətlə enerji yığır"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Yavaş enerji yığır"</string>
- <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
- <skip />
- <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
- <skip />
+ <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Batareyanı qorumaq üçün şarj gözlədilir"</string>
+ <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Şarj aksesuarını yoxlayın"</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"Şəbəkə kilidlidir"</string>
<string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"SIM yoxdur"</string>
<string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"İstifadəyə yararsız SIM."</string>
diff --git a/packages/SystemUI/res-keyguard/values-b+sr+Latn/strings.xml b/packages/SystemUI/res-keyguard/values-b+sr+Latn/strings.xml
index 519e5f6..d23ff41 100644
--- a/packages/SystemUI/res-keyguard/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-b+sr+Latn/strings.xml
@@ -33,10 +33,8 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Puni se"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Brzo se puni"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Sporo se puni"</string>
- <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
- <skip />
- <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
- <skip />
+ <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Punjenje je na čekanju da bi se zaštitila baterija"</string>
+ <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Proverite dodatnu opremu za punjenje"</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"Mreža je zaključana"</string>
<string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Nema SIM-a"</string>
<string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"Neupotrebljiv SIM."</string>
diff --git a/packages/SystemUI/res-keyguard/values-be/strings.xml b/packages/SystemUI/res-keyguard/values-be/strings.xml
index 15bc616..e704c3c8 100644
--- a/packages/SystemUI/res-keyguard/values-be/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-be/strings.xml
@@ -33,10 +33,8 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Ідзе зарадка"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Ідзе хуткая зарадка"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Ідзе павольная зарадка"</string>
- <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
- <skip />
- <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
- <skip />
+ <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Зарадка прыпынена, каб абараніць акумулятар"</string>
+ <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Праверце зарадную прыладу"</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"Сетка заблакіравана"</string>
<string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Няма SIM-карты"</string>
<string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"Непрыдатная для выкарыстання SIM-карта."</string>
diff --git a/packages/SystemUI/res-keyguard/values-bg/strings.xml b/packages/SystemUI/res-keyguard/values-bg/strings.xml
index 7e2e2b3..795d4b83 100644
--- a/packages/SystemUI/res-keyguard/values-bg/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-bg/strings.xml
@@ -33,10 +33,8 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Зарежда се"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Зарежда се бързо"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Зарежда се бавно"</string>
- <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
- <skip />
- <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
- <skip />
+ <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Зареждането е поставено на пауза с цел запазване на батерията"</string>
+ <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Проверете аксесоара за зареждане"</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"Мрежата е заключена"</string>
<string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Няма SIM карта"</string>
<string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"Неизползваема SIM карта."</string>
diff --git a/packages/SystemUI/res-keyguard/values-bn/strings.xml b/packages/SystemUI/res-keyguard/values-bn/strings.xml
index 2f7d3ba..e333ddd 100644
--- a/packages/SystemUI/res-keyguard/values-bn/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-bn/strings.xml
@@ -33,10 +33,8 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • চার্জ হচ্ছে"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • দ্রুত চার্জ হচ্ছে"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ধীরে চার্জ হচ্ছে"</string>
- <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
- <skip />
- <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
- <skip />
+ <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ব্যাটারিকে সুরক্ষিত রাখতে চার্জিং হোল্ড করা হয়েছে"</string>
+ <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • চার্জিং অ্যাক্সেসরি চেক করুন"</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"নেটওয়ার্ক লক করা আছে"</string>
<string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"কোনও সিম নেই"</string>
<string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"ব্যবহারযোগ্য নয় এমন সিম।"</string>
diff --git a/packages/SystemUI/res-keyguard/values-bs/strings.xml b/packages/SystemUI/res-keyguard/values-bs/strings.xml
index e35298b..75fe286 100644
--- a/packages/SystemUI/res-keyguard/values-bs/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-bs/strings.xml
@@ -33,10 +33,8 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Punjenje"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Brzo punjenje"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Sporo punjenje"</string>
- <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
- <skip />
- <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
- <skip />
+ <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Punjenje je na čekanju radi zaštite baterije"</string>
+ <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Provjera dodatne opreme za punjenje"</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"Mreža je zaključana"</string>
<string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Nema SIM-a"</string>
<string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"Neupotrebljiv SIM."</string>
diff --git a/packages/SystemUI/res-keyguard/values-ca/strings.xml b/packages/SystemUI/res-keyguard/values-ca/strings.xml
index 0fcc491..4047d7c 100644
--- a/packages/SystemUI/res-keyguard/values-ca/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ca/strings.xml
@@ -33,10 +33,8 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • S\'està carregant"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • S\'està carregant ràpidament"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • S\'està carregant lentament"</string>
- <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
- <skip />
- <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
- <skip />
+ <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • La càrrega s\'ha posat en espera per protegir la bateria"</string>
+ <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Revisa l\'accessori de càrrega"</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"La xarxa està bloquejada"</string>
<string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"No hi ha cap SIM"</string>
<string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"La SIM no es pot utilitzar."</string>
diff --git a/packages/SystemUI/res-keyguard/values-cs/strings.xml b/packages/SystemUI/res-keyguard/values-cs/strings.xml
index 3764032..ea9a683 100644
--- a/packages/SystemUI/res-keyguard/values-cs/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-cs/strings.xml
@@ -33,10 +33,8 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Nabíjení"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Rychlé nabíjení"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Pomalé nabíjení"</string>
- <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
- <skip />
- <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
- <skip />
+ <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Nabíjení je odloženo za účelem ochrany baterie"</string>
+ <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Zkontrolujte nabíjecí příslušenství"</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"Síť je blokována"</string>
<string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Žádná SIM karta"</string>
<string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"SIM kartu nelze použít."</string>
diff --git a/packages/SystemUI/res-keyguard/values-da/strings.xml b/packages/SystemUI/res-keyguard/values-da/strings.xml
index 8b04c46..8794bc0 100644
--- a/packages/SystemUI/res-keyguard/values-da/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-da/strings.xml
@@ -33,10 +33,8 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Oplader"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Oplader hurtigt"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Oplader langsomt"</string>
- <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
- <skip />
- <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
- <skip />
+ <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Opladningen er sat på pause for at beskytte batteriet"</string>
+ <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Tjek opladningstilbehøret"</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"Netværket er låst"</string>
<string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Intet SIM-kort"</string>
<string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"Deaktiveret SIM-kort."</string>
diff --git a/packages/SystemUI/res-keyguard/values-de/strings.xml b/packages/SystemUI/res-keyguard/values-de/strings.xml
index f122f49..9e80b74 100644
--- a/packages/SystemUI/res-keyguard/values-de/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-de/strings.xml
@@ -33,10 +33,8 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Wird geladen"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Wird schnell geladen"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Wird langsam geladen"</string>
- <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
- <skip />
- <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
- <skip />
+ <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Ladevorgang zum Schutz des Akkus angehalten"</string>
+ <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Ladezubehör prüfen"</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"Netzwerk gesperrt"</string>
<string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Keine SIM-Karte"</string>
<string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"SIM-Karte ist nicht nutzbar."</string>
diff --git a/packages/SystemUI/res-keyguard/values-el/strings.xml b/packages/SystemUI/res-keyguard/values-el/strings.xml
index 9c05a29..b7d3250 100644
--- a/packages/SystemUI/res-keyguard/values-el/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-el/strings.xml
@@ -33,10 +33,8 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Φόρτιση"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Γρήγορη φόρτιση"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Αργή φόρτιση"</string>
- <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
- <skip />
- <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
- <skip />
+ <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Η φόρτιση τέθηκε σε αναμονή για την προστασία της μπαταρίας"</string>
+ <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Ελέγξτε το αξεσουάρ φόρτισης"</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"Κλειδωμένο δίκτυο"</string>
<string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Δεν υπάρχει SIM"</string>
<string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"Η SIM δεν μπορεί να χρησιμοποιηθεί."</string>
diff --git a/packages/SystemUI/res-keyguard/values-en-rAU/strings.xml b/packages/SystemUI/res-keyguard/values-en-rAU/strings.xml
index fc8790c..d0461c1 100644
--- a/packages/SystemUI/res-keyguard/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-en-rAU/strings.xml
@@ -33,10 +33,8 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Charging"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Charging rapidly"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Charging slowly"</string>
- <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
- <skip />
- <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
- <skip />
+ <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Charging on hold to protect battery"</string>
+ <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Check charging accessory"</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"Network locked"</string>
<string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"No SIM"</string>
<string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"Unusable SIM."</string>
diff --git a/packages/SystemUI/res-keyguard/values-en-rGB/strings.xml b/packages/SystemUI/res-keyguard/values-en-rGB/strings.xml
index fc8790c..d0461c1 100644
--- a/packages/SystemUI/res-keyguard/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-en-rGB/strings.xml
@@ -33,10 +33,8 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Charging"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Charging rapidly"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Charging slowly"</string>
- <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
- <skip />
- <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
- <skip />
+ <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Charging on hold to protect battery"</string>
+ <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Check charging accessory"</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"Network locked"</string>
<string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"No SIM"</string>
<string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"Unusable SIM."</string>
diff --git a/packages/SystemUI/res-keyguard/values-en-rIN/strings.xml b/packages/SystemUI/res-keyguard/values-en-rIN/strings.xml
index fc8790c..d0461c1 100644
--- a/packages/SystemUI/res-keyguard/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-en-rIN/strings.xml
@@ -33,10 +33,8 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Charging"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Charging rapidly"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Charging slowly"</string>
- <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
- <skip />
- <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
- <skip />
+ <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Charging on hold to protect battery"</string>
+ <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Check charging accessory"</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"Network locked"</string>
<string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"No SIM"</string>
<string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"Unusable SIM."</string>
diff --git a/packages/SystemUI/res-keyguard/values-es-rUS/strings.xml b/packages/SystemUI/res-keyguard/values-es-rUS/strings.xml
index 3851b07..43aea8d 100644
--- a/packages/SystemUI/res-keyguard/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-es-rUS/strings.xml
@@ -33,10 +33,8 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Cargando"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Cargando rápidamente"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Cargando lentamente"</string>
- <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
- <skip />
- <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
- <skip />
+ <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Se detuvo la carga para proteger la batería"</string>
+ <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Verifica el accesorio de carga"</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"Bloqueada para la red"</string>
<string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"No hay ninguna tarjeta SIM"</string>
<string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"Tarjeta SIM inutilizable."</string>
diff --git a/packages/SystemUI/res-keyguard/values-es/strings.xml b/packages/SystemUI/res-keyguard/values-es/strings.xml
index c0fccdd..9022a3d 100644
--- a/packages/SystemUI/res-keyguard/values-es/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-es/strings.xml
@@ -33,10 +33,8 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Cargando"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Cargando rápidamente"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Cargando lentamente"</string>
- <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
- <skip />
- <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
- <skip />
+ <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Carga pausada para proteger la batería"</string>
+ <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Comprueba el accesorio de carga"</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"Bloqueada para la red"</string>
<string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"No hay ninguna SIM."</string>
<string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"No se puede usar la SIM."</string>
diff --git a/packages/SystemUI/res-keyguard/values-et/strings.xml b/packages/SystemUI/res-keyguard/values-et/strings.xml
index 5f75c87..c0d5e2f2 100644
--- a/packages/SystemUI/res-keyguard/values-et/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-et/strings.xml
@@ -33,10 +33,8 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Laadimine"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Kiirlaadimine"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Aeglane laadimine"</string>
- <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
- <skip />
- <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
- <skip />
+ <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • laadimine on aku kaitsmiseks ootele pandud"</string>
+ <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • kontrollige laadimistarvikut"</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"Võrk on lukus"</string>
<string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"SIM-i pole"</string>
<string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"SIM-i ei saa kasutada."</string>
diff --git a/packages/SystemUI/res-keyguard/values-eu/strings.xml b/packages/SystemUI/res-keyguard/values-eu/strings.xml
index 486531a..c9ac7e9 100644
--- a/packages/SystemUI/res-keyguard/values-eu/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-eu/strings.xml
@@ -33,10 +33,8 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Kargatzen"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Bizkor kargatzen"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Mantso kargatzen"</string>
- <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
- <skip />
- <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
- <skip />
+ <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • kargatze-prozesua zain dago bateria babesteko"</string>
+ <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Eman begiratu bat kargatzeko osagarriari"</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"Sarea blokeatuta dago"</string>
<string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Ez dago SIMik"</string>
<string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"Ezin da erabili SIMa."</string>
diff --git a/packages/SystemUI/res-keyguard/values-fa/strings.xml b/packages/SystemUI/res-keyguard/values-fa/strings.xml
index 4822487..b1b1f8a 100644
--- a/packages/SystemUI/res-keyguard/values-fa/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-fa/strings.xml
@@ -33,10 +33,8 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • درحال شارژ شدن"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • درحال شارژ سریع"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • آهستهآهسته شارژ میشود"</string>
- <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
- <skip />
- <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
- <skip />
+ <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • برای محافظت از باتری، شارژ موقتاً متوقف شده است"</string>
+ <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • لوازم شارژ را بررسی کنید"</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"شبکه قفل شد"</string>
<string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"سیمکارتی وجود ندارد"</string>
<string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"سیمکارت قابلاستفاده نیست."</string>
diff --git a/packages/SystemUI/res-keyguard/values-fi/strings.xml b/packages/SystemUI/res-keyguard/values-fi/strings.xml
index 39b0529..f5a6759 100644
--- a/packages/SystemUI/res-keyguard/values-fi/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-fi/strings.xml
@@ -33,10 +33,8 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Ladataan"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Ladataan nopeasti"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Ladataan hitaasti"</string>
- <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
- <skip />
- <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
- <skip />
+ <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Lataus on keskeytetty akun suojaamiseksi"</string>
+ <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Tarkista latauslisävaruste"</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"Verkko lukittu"</string>
<string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Ei SIM-korttia"</string>
<string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"SIM-korttia ei voi käyttää."</string>
diff --git a/packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml b/packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml
index fcf5052..bca8dd7 100644
--- a/packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml
@@ -33,10 +33,8 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"En recharge : <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"En recharge rapide : <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"En recharge lente : <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
- <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
- <skip />
- <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
- <skip />
+ <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • La recharge a été mise en pause pour protéger la pile"</string>
+ <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Vérifier l\'accessoire de recharge"</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"Réseau verrouillé"</string>
<string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Aucune carte SIM"</string>
<string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"La carte SIM est inutilisable."</string>
diff --git a/packages/SystemUI/res-keyguard/values-fr/strings.xml b/packages/SystemUI/res-keyguard/values-fr/strings.xml
index ffa0b1d..97d2081 100644
--- a/packages/SystemUI/res-keyguard/values-fr/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-fr/strings.xml
@@ -33,10 +33,8 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Recharge…"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Recharge rapide…"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Recharge lente"</string>
- <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
- <skip />
- <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
- <skip />
+ <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Recharge en pause pour protéger la batterie"</string>
+ <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Vérifier l\'accessoire de recharge"</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"Réseau verrouillé"</string>
<string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Aucune SIM"</string>
<string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"SIM inutilisable."</string>
diff --git a/packages/SystemUI/res-keyguard/values-gl/strings.xml b/packages/SystemUI/res-keyguard/values-gl/strings.xml
index 1163ed0..12b6c2c 100644
--- a/packages/SystemUI/res-keyguard/values-gl/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-gl/strings.xml
@@ -33,10 +33,8 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Cargando"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Cargando rapidamente"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Cargando lentamente"</string>
- <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
- <skip />
- <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
- <skip />
+ <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • A carga púxose en pausa para protexer a batería"</string>
+ <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Comproba o accesorio de carga"</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"Bloqueada pola rede"</string>
<string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Non hai ningunha SIM"</string>
<string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"A SIM non se pode usar."</string>
diff --git a/packages/SystemUI/res-keyguard/values-gu/strings.xml b/packages/SystemUI/res-keyguard/values-gu/strings.xml
index bfbb2f2..9e2fd53 100644
--- a/packages/SystemUI/res-keyguard/values-gu/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-gu/strings.xml
@@ -33,10 +33,8 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ચાર્જિંગ"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ઝડપથી ચાર્જિંગ"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ધીમેથી ચાર્જિંગ"</string>
- <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
- <skip />
- <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
- <skip />
+ <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • બૅટરીને સુરક્ષિત રાખવા માટે, ચાર્જિંગ હોલ્ડ પર રાખવામાં આવ્યું છે"</string>
+ <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ચાર્જિંગ ઍક્સેસરી ચેક કરો"</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"નેટવર્ક લૉક થયું"</string>
<string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"કોઈ સિમ કાર્ડ નથી"</string>
<string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"ઉપયોગમાં ન લઈ શકાતું સિમ કાર્ડ."</string>
diff --git a/packages/SystemUI/res-keyguard/values-hi/strings.xml b/packages/SystemUI/res-keyguard/values-hi/strings.xml
index 9ee840d..12cb7e3 100644
--- a/packages/SystemUI/res-keyguard/values-hi/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-hi/strings.xml
@@ -33,10 +33,8 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • चार्ज हो रहा है"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • तेज़ चार्ज हो रहा है"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • धीरे चार्ज हो रहा है"</string>
- <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
- <skip />
- <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
- <skip />
+ <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • बैटरी को सुरक्षित रखने के लिए, चार्जिंग को रोका गया है"</string>
+ <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • चार्जिंग ऐक्सेसरी की जांच करें"</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"नेटवर्क लॉक किया हुआ है"</string>
<string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"कोई सिम नहीं है"</string>
<string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"सिम को हमेशा के लिए बंद कर दिया गया है."</string>
diff --git a/packages/SystemUI/res-keyguard/values-hr/strings.xml b/packages/SystemUI/res-keyguard/values-hr/strings.xml
index 4edd7d2..fad222d 100644
--- a/packages/SystemUI/res-keyguard/values-hr/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-hr/strings.xml
@@ -33,10 +33,8 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • punjenje"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • brzo punjenje"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • sporo punjenje"</string>
- <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
- <skip />
- <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
- <skip />
+ <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Punjenje je pauzirano radi zaštite baterije"</string>
+ <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Provjerite dodatak za punjenje"</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"Mreža je zaključana"</string>
<string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Nema SIM-a"</string>
<string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"SIM je neupotrebljiv."</string>
diff --git a/packages/SystemUI/res-keyguard/values-hu/strings.xml b/packages/SystemUI/res-keyguard/values-hu/strings.xml
index f27156d..a22fbce 100644
--- a/packages/SystemUI/res-keyguard/values-hu/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-hu/strings.xml
@@ -33,10 +33,8 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Töltés"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Gyors töltés"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Lassú töltés"</string>
- <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
- <skip />
- <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
- <skip />
+ <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Az akkumulátor védelme érdekében a töltés szünetel"</string>
+ <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Ellenőrizze a töltőtartozékot"</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"Hálózat zárolva"</string>
<string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Nincs SIM"</string>
<string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"Nem használható SIM."</string>
diff --git a/packages/SystemUI/res-keyguard/values-hy/strings.xml b/packages/SystemUI/res-keyguard/values-hy/strings.xml
index a402721..119928a 100644
--- a/packages/SystemUI/res-keyguard/values-hy/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-hy/strings.xml
@@ -33,10 +33,8 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Լիցքավորում"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Արագ լիցքավորում"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Դանդաղ լիցքավորում"</string>
- <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
- <skip />
- <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
- <skip />
+ <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Լիցքավորումը դադարեցվել է՝ մարտկոցը պաշտպանելու համար"</string>
+ <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Ստուգեք լիցքավորիչը"</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"Ցանցը կողպված է"</string>
<string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"SIM քարտ չկա"</string>
<string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"Անվավեր SIM քարտ։"</string>
diff --git a/packages/SystemUI/res-keyguard/values-in/strings.xml b/packages/SystemUI/res-keyguard/values-in/strings.xml
index 229419e..f4db035 100644
--- a/packages/SystemUI/res-keyguard/values-in/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-in/strings.xml
@@ -33,10 +33,8 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Mengisi daya"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Mengisi daya dengan cepat"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Mengisi daya dengan lambat"</string>
- <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
- <skip />
- <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
- <skip />
+ <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Pengisian daya dihentikan sementara untuk melindungi baterai"</string>
+ <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Periksa aksesori pengisi daya"</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"Jaringan terkunci"</string>
<string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Tidak ada SIM"</string>
<string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"SIM tidak dapat digunakan."</string>
diff --git a/packages/SystemUI/res-keyguard/values-is/strings.xml b/packages/SystemUI/res-keyguard/values-is/strings.xml
index 7edcdbd..c364f60 100644
--- a/packages/SystemUI/res-keyguard/values-is/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-is/strings.xml
@@ -33,10 +33,8 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Í hleðslu"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Hröð hleðsla"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Hæg hleðsla"</string>
- <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
- <skip />
- <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
- <skip />
+ <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Hleðsla í bið til að vernda rafhlöðuna"</string>
+ <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Athugaðu hleðslubúnaðinn"</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"Net læst"</string>
<string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Ekkert SIM-kort"</string>
<string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"Ónothæft SIM-kort."</string>
diff --git a/packages/SystemUI/res-keyguard/values-it/strings.xml b/packages/SystemUI/res-keyguard/values-it/strings.xml
index 7856a49..659928f 100644
--- a/packages/SystemUI/res-keyguard/values-it/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-it/strings.xml
@@ -33,10 +33,8 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • In carica"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Ricarica veloce"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Ricarica lenta"</string>
- <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
- <skip />
- <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
- <skip />
+ <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Ricarica in sospeso per proteggere la batteria"</string>
+ <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Controlla l\'accessorio di ricarica"</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"Rete bloccata"</string>
<string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Nessuna SIM presente"</string>
<string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"SIM inutilizzabile."</string>
diff --git a/packages/SystemUI/res-keyguard/values-iw/strings.xml b/packages/SystemUI/res-keyguard/values-iw/strings.xml
index 9182c5a..0021d0a 100644
--- a/packages/SystemUI/res-keyguard/values-iw/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-iw/strings.xml
@@ -33,10 +33,8 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • בטעינה"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • בטעינה מהירה"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • בטעינה איטית"</string>
- <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
- <skip />
- <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
- <skip />
+ <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • הטעינה הושהתה כדי להגן על הסוללה"</string>
+ <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • צריך לבדוק את אביזר הטעינה"</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"הרשת נעולה"</string>
<string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"אין כרטיס SIM"</string>
<string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"לא ניתן להשתמש בכרטיס ה-SIM הזה."</string>
diff --git a/packages/SystemUI/res-keyguard/values-ja/strings.xml b/packages/SystemUI/res-keyguard/values-ja/strings.xml
index e589f85..c94d6b1 100644
--- a/packages/SystemUI/res-keyguard/values-ja/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ja/strings.xml
@@ -33,10 +33,8 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • 充電中"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • 急速充電中"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • 低速充電中"</string>
- <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
- <skip />
- <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
- <skip />
+ <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • バッテリーを保護するため、充電を一時停止しています"</string>
+ <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • 充電用アクセサリを確認してください"</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"ネットワークがロックされました"</string>
<string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"SIM がありません"</string>
<string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"SIM が使用できません。"</string>
diff --git a/packages/SystemUI/res-keyguard/values-ka/strings.xml b/packages/SystemUI/res-keyguard/values-ka/strings.xml
index 0fe5a39..c36b471 100644
--- a/packages/SystemUI/res-keyguard/values-ka/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ka/strings.xml
@@ -33,10 +33,8 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • იტენება"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • სწრაფად იტენება"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ნელა იტენება"</string>
- <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
- <skip />
- <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
- <skip />
+ <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • დატენვა შეჩერებულია ბატარეის დასაცავად"</string>
+ <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • შეამოწმეთ დამტენი აქსესუარი"</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"ქსელი ჩაკეტილია"</string>
<string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"SIM არ არის"</string>
<string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"გამოუყენებელი SIM."</string>
diff --git a/packages/SystemUI/res-keyguard/values-kk/strings.xml b/packages/SystemUI/res-keyguard/values-kk/strings.xml
index 3882c5d..fef02be 100644
--- a/packages/SystemUI/res-keyguard/values-kk/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-kk/strings.xml
@@ -33,10 +33,8 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Зарядталуда"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Жылдам зарядтау"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Баяу зарядталуда"</string>
- <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
- <skip />
- <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
- <skip />
+ <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Батареяны қорғау мақсатында зарядтау кідіртілді."</string>
+ <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Зарядтау құрылғысын тексеріңіз."</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"Желі құлыптаулы"</string>
<string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"SIM картасы жоқ."</string>
<string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"SIM картасын пайдалану мүмкін емес."</string>
diff --git a/packages/SystemUI/res-keyguard/values-km/strings.xml b/packages/SystemUI/res-keyguard/values-km/strings.xml
index 0ebda04..f82defd 100644
--- a/packages/SystemUI/res-keyguard/values-km/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-km/strings.xml
@@ -33,10 +33,8 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • កំពុងសាកថ្ម"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • កំពុងសាកថ្មយ៉ាងឆាប់រហ័ស"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • កំពុងសាកថ្មយឺត"</string>
- <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
- <skip />
- <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
- <skip />
+ <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • កំពុងផ្អាកការសាកថ្ម ដើម្បីការពារថ្ម"</string>
+ <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ពិនិត្យមើលគ្រឿងសាកថ្ម"</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"បណ្ដាញជាប់សោ"</string>
<string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"គ្មានស៊ីមទេ"</string>
<string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"ស៊ីមមិនអាចប្រើបាន។"</string>
diff --git a/packages/SystemUI/res-keyguard/values-kn/strings.xml b/packages/SystemUI/res-keyguard/values-kn/strings.xml
index 4dbefed..4ab035e5 100644
--- a/packages/SystemUI/res-keyguard/values-kn/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-kn/strings.xml
@@ -33,10 +33,8 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ಚಾರ್ಜ್ ಮಾಡಲಾಗುತ್ತಿದೆ"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ವೇಗವಾಗಿ ಚಾರ್ಜ್ಮಾಡಲಾಗುತ್ತಿದೆ"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ನಿಧಾನವಾಗಿ ಚಾರ್ಜ್ ಮಾಡಲಾಗುತ್ತಿದೆ"</string>
- <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
- <skip />
- <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
- <skip />
+ <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ಬ್ಯಾಟರಿಯನ್ನು ರಕ್ಷಿಸಲು ಚಾರ್ಜಿಂಗ್ ಅನ್ನು ಹೋಲ್ಡ್ ಮಾಡಲಾಗಿದೆ"</string>
+ <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ಚಾರ್ಜಿಂಗ್ ಪರಿಕರವನ್ನು ಪರಿಶೀಲಿಸಿ"</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"ನೆಟ್ವರ್ಕ್ ಲಾಕ್ ಆಗಿದೆ"</string>
<string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"SIM ಇಲ್ಲ"</string>
<string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"SIM ನಿಷ್ಪ್ರಯೋಜಕವಾಗಿದೆ."</string>
diff --git a/packages/SystemUI/res-keyguard/values-ko/strings.xml b/packages/SystemUI/res-keyguard/values-ko/strings.xml
index e0d7645..d456366 100644
--- a/packages/SystemUI/res-keyguard/values-ko/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ko/strings.xml
@@ -33,10 +33,8 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • 충전 중"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • 고속 충전 중"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • 저속 충전 중"</string>
- <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
- <skip />
- <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
- <skip />
+ <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • 배터리 보호를 위해 충전 일시중지"</string>
+ <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • 충전 액세서리 확인"</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"네트워크 잠김"</string>
<string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"SIM 없음"</string>
<string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"SIM을 사용할 수 없습니다."</string>
diff --git a/packages/SystemUI/res-keyguard/values-ky/strings.xml b/packages/SystemUI/res-keyguard/values-ky/strings.xml
index cc777a2..e8640ae5 100644
--- a/packages/SystemUI/res-keyguard/values-ky/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ky/strings.xml
@@ -33,10 +33,8 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Кубатталууда"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Тез кубатталууда"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Жай кубатталууда"</string>
- <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
- <skip />
- <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
- <skip />
+ <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Батареяны коргоо үчүн кубаттоо тындырылды"</string>
+ <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Кубаттоо шайманын текшериңиз"</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"Тармак кулпуланган"</string>
<string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"SIM карта жок"</string>
<string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"Жараксыз SIM карта."</string>
diff --git a/packages/SystemUI/res-keyguard/values-lo/strings.xml b/packages/SystemUI/res-keyguard/values-lo/strings.xml
index ce2fa3b..6f6c1d1 100644
--- a/packages/SystemUI/res-keyguard/values-lo/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-lo/strings.xml
@@ -33,10 +33,8 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ກຳລັງສາກ"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ກຳລັງສາກແບບດ່ວນ"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ກຳລັງສາກແບບຊ້າ"</string>
- <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
- <skip />
- <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
- <skip />
+ <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ຢຸດການສາກຊົ່ວຄາວເພື່ອປົກປ້ອງແບັດເຕີຣີ"</string>
+ <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ກວດສອບອຸປະກອນເສີມສຳລັບການສາກ"</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"ເຄືອຂ່າຍຖືກລັອກ"</string>
<string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"ບໍ່ມີຊິມ"</string>
<string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"ຊິມໃຊ້ບໍ່ໄດ້."</string>
diff --git a/packages/SystemUI/res-keyguard/values-lt/strings.xml b/packages/SystemUI/res-keyguard/values-lt/strings.xml
index 4344b61..9d13485 100644
--- a/packages/SystemUI/res-keyguard/values-lt/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-lt/strings.xml
@@ -33,10 +33,8 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Įkraunama"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Greitai įkraunama"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Lėtai įkraunama"</string>
- <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
- <skip />
- <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
- <skip />
+ <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • įkrovimas pristabdytas, siekiant apsaugoti akumuliatorių"</string>
+ <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • patikrinkite įkrovimo priedą"</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"Tinklas užrakintas"</string>
<string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Nėra SIM kortelės"</string>
<string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"Nenaudojama SIM kortelė."</string>
diff --git a/packages/SystemUI/res-keyguard/values-lv/strings.xml b/packages/SystemUI/res-keyguard/values-lv/strings.xml
index b521511..10d657b 100644
--- a/packages/SystemUI/res-keyguard/values-lv/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-lv/strings.xml
@@ -33,10 +33,8 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Notiek uzlāde"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Notiek ātrā uzlāde"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Notiek lēnā uzlāde"</string>
- <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
- <skip />
- <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
- <skip />
+ <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Uzlāde apturēta, lai aizsargātu akumulatoru"</string>
+ <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Pārbaudiet uzlādes piederumu"</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"Tīkls ir bloķēts."</string>
<string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Nav SIM kartes"</string>
<string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"SIM karte nav izmantojama."</string>
diff --git a/packages/SystemUI/res-keyguard/values-mk/strings.xml b/packages/SystemUI/res-keyguard/values-mk/strings.xml
index 7fe966f..9aafb86 100644
--- a/packages/SystemUI/res-keyguard/values-mk/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-mk/strings.xml
@@ -33,10 +33,8 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Се полни"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Брзо полнење"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Бавно полнење"</string>
- <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
- <skip />
- <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
- <skip />
+ <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Полнењето е паузирано за да се заштити батеријата"</string>
+ <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Проверете го додатокот за полнење"</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"Мрежата е заклучена"</string>
<string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Нема SIM-картичка"</string>
<string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"SIM-картичката е неупотреблива."</string>
diff --git a/packages/SystemUI/res-keyguard/values-ml/strings.xml b/packages/SystemUI/res-keyguard/values-ml/strings.xml
index afd7c40..f690ce5 100644
--- a/packages/SystemUI/res-keyguard/values-ml/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ml/strings.xml
@@ -33,10 +33,8 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ചാർജ് ചെയ്യുന്നു"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • വേഗത്തിൽ ചാർജ് ചെയ്യുന്നു"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • പതുക്കെ ചാർജ് ചെയ്യുന്നു"</string>
- <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
- <skip />
- <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
- <skip />
+ <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ബാറ്ററി പരിരക്ഷിക്കാൻ ചാർജിംഗ് ഹോൾഡിലാണ്"</string>
+ <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ചാർജിംഗ് ആക്സസറി പരിശോധിക്കുക"</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"നെറ്റ്വർക്ക് ലോക്കുചെയ്തു"</string>
<string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"സിം ഇല്ല"</string>
<string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"ഉപയോഗശൂന്യമായ സിം."</string>
diff --git a/packages/SystemUI/res-keyguard/values-mn/strings.xml b/packages/SystemUI/res-keyguard/values-mn/strings.xml
index d29daa5..70cfa37 100644
--- a/packages/SystemUI/res-keyguard/values-mn/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-mn/strings.xml
@@ -33,10 +33,8 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Цэнэглэж байна"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Хурдан цэнэглэж байна"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Удаан цэнэглэж байна"</string>
- <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
- <skip />
- <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
- <skip />
+ <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Батарейг хамгаалахын тулд цэнэглэхийг хүлээлгэсэн"</string>
+ <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Цэнэглэх нэмэлт хэрэгслийг шалгах"</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"Сүлжээ түгжигдсэн"</string>
<string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"SIM байхгүй"</string>
<string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"Ашиглах боломжгүй SIM."</string>
diff --git a/packages/SystemUI/res-keyguard/values-mr/strings.xml b/packages/SystemUI/res-keyguard/values-mr/strings.xml
index 85522d7..9da4fb0 100644
--- a/packages/SystemUI/res-keyguard/values-mr/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-mr/strings.xml
@@ -33,10 +33,8 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • चार्ज होत आहे"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • वेगाने चार्ज होत आहे"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • सावकाश चार्ज होत आहे"</string>
- <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
- <skip />
- <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
- <skip />
+ <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • बॅटरीचे संरक्षण करण्यासाठी चार्जिंग थांबवले आहे"</string>
+ <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • चार्जिंगसंबंधित ॲक्सेसरी तपासा"</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"नेटवर्क लॉक केले"</string>
<string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"सिम नाही"</string>
<string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"वापरण्यायोग्य नसलेले सिम."</string>
diff --git a/packages/SystemUI/res-keyguard/values-ms/strings.xml b/packages/SystemUI/res-keyguard/values-ms/strings.xml
index 1b8ef07..76de213 100644
--- a/packages/SystemUI/res-keyguard/values-ms/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ms/strings.xml
@@ -33,10 +33,8 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Mengecas"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Mengecas dengan cepat"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Mengecas dengan perlahan"</string>
- <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
- <skip />
- <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
- <skip />
+ <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Pengecasan ditunda untuk melindungi bateri"</string>
+ <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Periksa aksesori pengecasan"</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"Rangkaian dikunci"</string>
<string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Tiada SIM"</string>
<string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"SIM tidak boleh digunakan."</string>
diff --git a/packages/SystemUI/res-keyguard/values-my/strings.xml b/packages/SystemUI/res-keyguard/values-my/strings.xml
index a638d17d..bedabb8 100644
--- a/packages/SystemUI/res-keyguard/values-my/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-my/strings.xml
@@ -33,10 +33,8 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • အားသွင်းနေသည်"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • အမြန်အားသွင်းနေသည်"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • နှေးကွေးစွာ အားသွင်းနေသည်"</string>
- <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
- <skip />
- <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
- <skip />
+ <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ဘက်ထရီကို ကာကွယ်ရန် အားသွင်းခြင်းကို ခဏရပ်ထားသည်"</string>
+ <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • အားသွင်းပစ္စည်းကို စစ်ပါ"</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"ကွန်ရက်ကို လော့ခ်ချထားသည်"</string>
<string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"ဆင်းမ်ကတ် မရှိပါ"</string>
<string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"ဆင်းမ်ကတ်ကို သုံး၍မရပါ။"</string>
diff --git a/packages/SystemUI/res-keyguard/values-nb/strings.xml b/packages/SystemUI/res-keyguard/values-nb/strings.xml
index b289b72c..04b567b 100644
--- a/packages/SystemUI/res-keyguard/values-nb/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-nb/strings.xml
@@ -33,10 +33,8 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Lader"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Lader raskt"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Lader sakte"</string>
- <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
- <skip />
- <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
- <skip />
+ <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Ladingen er satt på vent for å beskytte batteriet"</string>
+ <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> · Sjekk ladetilbehøret"</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"Nettverket er låst"</string>
<string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Ingen SIM-kort"</string>
<string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"SIM-kortet kan ikke brukes."</string>
diff --git a/packages/SystemUI/res-keyguard/values-ne/strings.xml b/packages/SystemUI/res-keyguard/values-ne/strings.xml
index fc6f21fe..692e693 100644
--- a/packages/SystemUI/res-keyguard/values-ne/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ne/strings.xml
@@ -33,10 +33,8 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • चार्ज गरिँदै"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • द्रुत गतिमा चार्ज गरिँदै छ"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • मन्द गतिमा चार्ज गरिँदै"</string>
- <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
- <skip />
- <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
- <skip />
+ <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ब्याट्रीको सुरक्षा गर्न चार्जिङ होल्ड गरिएको छ"</string>
+ <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • चार्जिङ एक्सेसरी जाँच्नुहोस्"</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"नेटवर्क लक भएको छ"</string>
<string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"SIM कार्ड हालिएको छैन"</string>
<string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"यो SIM कार्ड प्रयोग गर्न मिल्दैन।"</string>
diff --git a/packages/SystemUI/res-keyguard/values-nl/strings.xml b/packages/SystemUI/res-keyguard/values-nl/strings.xml
index 093c7b7..9833505 100644
--- a/packages/SystemUI/res-keyguard/values-nl/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-nl/strings.xml
@@ -33,10 +33,8 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Opladen"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Snel opladen"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Langzaam opladen"</string>
- <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
- <skip />
- <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
- <skip />
+ <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Opladen in de wacht gezet om batterij te beschermen"</string>
+ <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Check je oplaadaccessoire"</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"Netwerk vergrendeld"</string>
<string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Geen simkaart"</string>
<string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"Onbruikbare simkaart."</string>
diff --git a/packages/SystemUI/res-keyguard/values-or/strings.xml b/packages/SystemUI/res-keyguard/values-or/strings.xml
index 76dbdaf..5ed2f11 100644
--- a/packages/SystemUI/res-keyguard/values-or/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-or/strings.xml
@@ -33,10 +33,8 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ଚାର୍ଜ ହେଉଛି"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ଦ୍ରୁତ ଭାବେ ଚାର୍ଜ ହେଉଛି"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ଧୀରେ ଚାର୍ଜ ହେଉଛି"</string>
- <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
- <skip />
- <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
- <skip />
+ <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ବେଟେରୀକୁ ସୁରକ୍ଷିତ ରଖିବା ପାଇଁ ଚାର୍ଜିଂ ହୋଲ୍ଡରେ ଅଛି"</string>
+ <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ଚାର୍ଜିଂ ଆକସେସୋରୀକୁ ଯାଞ୍ଚ କରନ୍ତୁ"</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"ନେଟୱର୍କକୁ ଲକ୍ କରାଯାଇଛି"</string>
<string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"କୌଣସି SIM ନାହିଁ"</string>
<string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"ବ୍ୟବହାର ଅଯୋଗ୍ୟ ଥିବା SIM।"</string>
diff --git a/packages/SystemUI/res-keyguard/values-pa/strings.xml b/packages/SystemUI/res-keyguard/values-pa/strings.xml
index 10e9eef..e591e5d2 100644
--- a/packages/SystemUI/res-keyguard/values-pa/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-pa/strings.xml
@@ -33,10 +33,8 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ਚਾਰਜ ਹੋ ਰਿਹਾ ਹੈ"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ਤੇਜ਼ੀ ਨਾਲ ਚਾਰਜ ਹੋ ਰਿਹਾ ਹੈ"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ਹੌਲੀ-ਹੌਲੀ ਚਾਰਜ ਹੋ ਰਿਹਾ ਹੈ"</string>
- <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
- <skip />
- <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
- <skip />
+ <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ਬੈਟਰੀ ਦੀ ਸੁਰੱਖਿਆ ਲਈ ਚਾਰਜਿੰਗ ਨੂੰ ਰੋਕਿਆ ਗਿਆ ਹੈ"</string>
+ <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ਚਾਰਜਿੰਗ ਐਕਸੈਸਰੀ ਦੀ ਜਾਂਚ ਕਰੋ"</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"ਨੈੱਟਵਰਕ ਲਾਕ ਕੀਤਾ ਗਿਆ"</string>
<string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"ਕੋਈ ਸਿਮ ਨਹੀਂ ਹੈ"</string>
<string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"ਬੇਕਾਰ ਸਿਮ।"</string>
diff --git a/packages/SystemUI/res-keyguard/values-pl/strings.xml b/packages/SystemUI/res-keyguard/values-pl/strings.xml
index 08cbc29..396fa79 100644
--- a/packages/SystemUI/res-keyguard/values-pl/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-pl/strings.xml
@@ -33,10 +33,8 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Ładowanie"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Szybkie ładowanie"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Wolne ładowanie"</string>
- <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
- <skip />
- <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
- <skip />
+ <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> – wstrzymano ładowanie, aby chronić baterię"</string>
+ <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> – sprawdź akcesoria do ładowania"</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"Sieć zablokowana"</string>
<string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Brak karty SIM"</string>
<string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"Nie można użyć karty SIM."</string>
diff --git a/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml b/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml
index efd1c75..3de54f9 100644
--- a/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml
@@ -33,10 +33,8 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Carregando"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Carregando rapidamente"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Carregando lentamente"</string>
- <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
- <skip />
- <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
- <skip />
+ <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Carregamento suspenso para proteger a bateria"</string>
+ <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Verifique o acessório de carregamento"</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"Rede bloqueada"</string>
<string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Sem chip"</string>
<string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"Chip inutilizável."</string>
diff --git a/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml b/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml
index 38cc437..3d8f7e6 100644
--- a/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml
@@ -33,10 +33,8 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • A carregar…"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • A carregar rapidamente…"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • A carregar lentamente…"</string>
- <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
- <skip />
- <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
- <skip />
+ <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Carregamento em espera para proteger a bateria"</string>
+ <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Verificar acessório de carregamento"</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"Rede bloqueada"</string>
<string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Sem SIM"</string>
<string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"SIM inutilizável."</string>
diff --git a/packages/SystemUI/res-keyguard/values-pt/strings.xml b/packages/SystemUI/res-keyguard/values-pt/strings.xml
index efd1c75..3de54f9 100644
--- a/packages/SystemUI/res-keyguard/values-pt/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-pt/strings.xml
@@ -33,10 +33,8 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Carregando"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Carregando rapidamente"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Carregando lentamente"</string>
- <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
- <skip />
- <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
- <skip />
+ <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Carregamento suspenso para proteger a bateria"</string>
+ <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Verifique o acessório de carregamento"</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"Rede bloqueada"</string>
<string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Sem chip"</string>
<string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"Chip inutilizável."</string>
diff --git a/packages/SystemUI/res-keyguard/values-ro/strings.xml b/packages/SystemUI/res-keyguard/values-ro/strings.xml
index e3cfd3e..053f862 100644
--- a/packages/SystemUI/res-keyguard/values-ro/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ro/strings.xml
@@ -33,10 +33,8 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Se încarcă"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Se încarcă rapid"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Se încarcă lent"</string>
- <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
- <skip />
- <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
- <skip />
+ <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Încărcarea s-a întrerupt pentru a proteja bateria"</string>
+ <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Verifică accesoriul de încărcare"</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"Rețea blocată"</string>
<string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Niciun card SIM"</string>
<string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"Cardul SIM nu se poate folosi."</string>
diff --git a/packages/SystemUI/res-keyguard/values-ru/strings.xml b/packages/SystemUI/res-keyguard/values-ru/strings.xml
index b5b3266..6be1489 100644
--- a/packages/SystemUI/res-keyguard/values-ru/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ru/strings.xml
@@ -33,10 +33,8 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"Идет зарядка (<xliff:g id="PERCENTAGE">%s</xliff:g>)"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"Идет быстрая зарядка (<xliff:g id="PERCENTAGE">%s</xliff:g>)"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"Идет медленная зарядка (<xliff:g id="PERCENTAGE">%s</xliff:g>)"</string>
- <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
- <skip />
- <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
- <skip />
+ <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Зарядка приостановлена для защиты батареи."</string>
+ <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Проверьте зарядное устройство."</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"Сеть заблокирована"</string>
<string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"SIM-карта отсутствует"</string>
<string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"SIM-карту невозможно использовать."</string>
diff --git a/packages/SystemUI/res-keyguard/values-si/strings.xml b/packages/SystemUI/res-keyguard/values-si/strings.xml
index ecd3f3f..401e147 100644
--- a/packages/SystemUI/res-keyguard/values-si/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-si/strings.xml
@@ -33,10 +33,8 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ආරෝපණය වෙමින්"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • වේගයෙන් ආරෝපණය වෙමින්"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • සෙමින් ආරෝපණය වෙමින්"</string>
- <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
- <skip />
- <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
- <skip />
+ <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • බැටරිය ආරක්ෂා කිරීම සඳහා ආරෝපණය රඳවා තබා ඇත"</string>
+ <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ආරෝපණ ආයිත්තම පරීක්ෂා කරන්න"</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"ජාලය අගුළු දමා ඇත"</string>
<string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"SIM නැත"</string>
<string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"භාවිත කළ නොහැකි SIM."</string>
diff --git a/packages/SystemUI/res-keyguard/values-sk/strings.xml b/packages/SystemUI/res-keyguard/values-sk/strings.xml
index c38ba64..2b65466 100644
--- a/packages/SystemUI/res-keyguard/values-sk/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sk/strings.xml
@@ -33,10 +33,8 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Nabíja sa"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Nabíja sa rýchlo"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Nabíja sa pomaly"</string>
- <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
- <skip />
- <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
- <skip />
+ <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Nabíjanie je pozastavené, aby sa chránila batéria"</string>
+ <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Skontrolujte nabíjacie príslušenstvo"</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"Sieť je zablokovaná"</string>
<string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Žiadna SIM karta"</string>
<string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"Nepoužiteľná SIM karta."</string>
diff --git a/packages/SystemUI/res-keyguard/values-sl/strings.xml b/packages/SystemUI/res-keyguard/values-sl/strings.xml
index c066f50..dbb34c9 100644
--- a/packages/SystemUI/res-keyguard/values-sl/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sl/strings.xml
@@ -33,10 +33,8 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • polnjenje"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • hitro polnjenje"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • počasno polnjenje"</string>
- <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
- <skip />
- <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
- <skip />
+ <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Zaradi zaščite baterije je polnjenje na čakanju"</string>
+ <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Preverite pripomoček za polnjenje"</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"Omrežje je zaklenjeno"</string>
<string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Ni kartice SIM."</string>
<string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"Kartica SIM je neuporabna."</string>
diff --git a/packages/SystemUI/res-keyguard/values-sq/strings.xml b/packages/SystemUI/res-keyguard/values-sq/strings.xml
index 1dc93fd1..00c4999 100644
--- a/packages/SystemUI/res-keyguard/values-sq/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sq/strings.xml
@@ -33,10 +33,8 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Po karikohet"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Po karikohet me shpejtësi"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Po karikohet ngadalë"</string>
- <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
- <skip />
- <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
- <skip />
+ <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Karikimi është vendosur në pritje për të mbrojtur baterinë"</string>
+ <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Kontrollo aksesorin e karikimit"</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"Rrjeti është i kyçur"</string>
<string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Nuk ka kartë SIM"</string>
<string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"Kartë SIM e papërdorshme."</string>
diff --git a/packages/SystemUI/res-keyguard/values-sr/strings.xml b/packages/SystemUI/res-keyguard/values-sr/strings.xml
index 34cb06b..feac583 100644
--- a/packages/SystemUI/res-keyguard/values-sr/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sr/strings.xml
@@ -33,10 +33,8 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Пуни се"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Брзо се пуни"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Споро се пуни"</string>
- <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
- <skip />
- <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
- <skip />
+ <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Пуњење је на чекању да би се заштитила батерија"</string>
+ <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Проверите додатну опрему за пуњење"</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"Мрежа је закључана"</string>
<string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Нема SIM-а"</string>
<string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"Неупотребљив SIM."</string>
diff --git a/packages/SystemUI/res-keyguard/values-sv/strings.xml b/packages/SystemUI/res-keyguard/values-sv/strings.xml
index 76c5dca..67fa2f7 100644
--- a/packages/SystemUI/res-keyguard/values-sv/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sv/strings.xml
@@ -33,10 +33,8 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Laddas"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Laddas snabbt"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Laddas långsamt"</string>
- <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
- <skip />
- <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
- <skip />
+ <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Laddningen har pausats för att skydda batteriet"</string>
+ <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Kontrollera laddningstillbehöret"</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"Nätverk låst"</string>
<string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Inget SIM-kort"</string>
<string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"SIM-kortet går inte att använda."</string>
diff --git a/packages/SystemUI/res-keyguard/values-sw/strings.xml b/packages/SystemUI/res-keyguard/values-sw/strings.xml
index b310ab9..527e73e 100644
--- a/packages/SystemUI/res-keyguard/values-sw/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sw/strings.xml
@@ -33,10 +33,8 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Inachaji"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Inachaji kwa kasi"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Inachaji pole pole"</string>
- <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
- <skip />
- <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
- <skip />
+ <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Imesitisha kuchaji ili kulinda betri yako"</string>
+ <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Kagua kifaa cha kuchaji"</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"Mtandao umefungwa"</string>
<string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Hakuna SIM"</string>
<string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"SIM haiwezi kutumika."</string>
diff --git a/packages/SystemUI/res-keyguard/values-ta/strings.xml b/packages/SystemUI/res-keyguard/values-ta/strings.xml
index f31137a..05ac0c0 100644
--- a/packages/SystemUI/res-keyguard/values-ta/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ta/strings.xml
@@ -33,10 +33,8 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • சார்ஜாகிறது"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • வேகமாகச் சார்ஜாகிறது"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • மெதுவாகச் சார்ஜாகிறது"</string>
- <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
- <skip />
- <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
- <skip />
+ <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • பேட்டரியைப் பாதுகாப்பதற்காகச் சார்ஜிங் ஹோல்டு செய்யப்பட்டுள்ளது"</string>
+ <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • சார்ஜிங் துணைக்கருவியைச் சரிபார்க்கவும்"</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"நெட்வொர்க் பூட்டப்பட்டது"</string>
<string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"சிம் இல்லை"</string>
<string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"பயன்படுத்த முடியாத சிம்."</string>
diff --git a/packages/SystemUI/res-keyguard/values-te/strings.xml b/packages/SystemUI/res-keyguard/values-te/strings.xml
index 924678f..9d37fc1 100644
--- a/packages/SystemUI/res-keyguard/values-te/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-te/strings.xml
@@ -33,10 +33,8 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ఛార్జ్ అవుతోంది"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • వేగంగా ఛార్జ్ అవుతోంది"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • నెమ్మదిగా ఛార్జ్ అవుతోంది"</string>
- <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
- <skip />
- <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
- <skip />
+ <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • బ్యాటరీని రక్షించడానికి ఛార్జింగ్ హోల్డ్లో ఉంచబడింది"</string>
+ <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ఛార్జింగ్ యాక్సెసరీని చెక్ చేయండి"</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"నెట్వర్క్ లాక్ చేయబడింది"</string>
<string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"SIM లేదు"</string>
<string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"వినియోగించలేని SIM."</string>
diff --git a/packages/SystemUI/res-keyguard/values-th/strings.xml b/packages/SystemUI/res-keyguard/values-th/strings.xml
index 980ed99..57aadea 100644
--- a/packages/SystemUI/res-keyguard/values-th/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-th/strings.xml
@@ -33,10 +33,8 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • กำลังชาร์จ"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • กำลังชาร์จอย่างเร็ว"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • กำลังชาร์จอย่างช้าๆ"</string>
- <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
- <skip />
- <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
- <skip />
+ <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • หยุดการชาร์จชั่วคราวเพื่อถนอมแบตเตอรี่"</string>
+ <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ตรวจสอบอุปกรณ์เสริมสำหรับการชาร์จ"</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"เครือข่ายถูกล็อก"</string>
<string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"ไม่มี SIM"</string>
<string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"SIM ใช้งานไม่ได้"</string>
diff --git a/packages/SystemUI/res-keyguard/values-tl/strings.xml b/packages/SystemUI/res-keyguard/values-tl/strings.xml
index b054b1e..bb7c344 100644
--- a/packages/SystemUI/res-keyguard/values-tl/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-tl/strings.xml
@@ -33,10 +33,8 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Nagcha-charge"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Mabilis na nagcha-charge"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Mabagal na nagcha-charge"</string>
- <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
- <skip />
- <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
- <skip />
+ <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Naka-hold ang pag-charge para protektahan ang baterya"</string>
+ <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Suriin ang accessory sa pag-charge"</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"Naka-lock ang network"</string>
<string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Walang SIM"</string>
<string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"Hindi magagamit na SIM."</string>
diff --git a/packages/SystemUI/res-keyguard/values-tr/strings.xml b/packages/SystemUI/res-keyguard/values-tr/strings.xml
index 343cea1..f401629 100644
--- a/packages/SystemUI/res-keyguard/values-tr/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-tr/strings.xml
@@ -33,10 +33,8 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Şarj oluyor"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Hızlı şarj oluyor"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Yavaş şarj oluyor"</string>
- <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
- <skip />
- <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
- <skip />
+ <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Pili korumak için şarj beklemede"</string>
+ <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Şarj aksesuarını kontrol edin"</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"Ağ kilitli"</string>
<string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"SIM yok"</string>
<string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"Kullanılamayan SIM."</string>
diff --git a/packages/SystemUI/res-keyguard/values-uk/strings.xml b/packages/SystemUI/res-keyguard/values-uk/strings.xml
index 56ca79d..4330b32 100644
--- a/packages/SystemUI/res-keyguard/values-uk/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-uk/strings.xml
@@ -33,10 +33,8 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Заряджання"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Швидке заряджання"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Повільне заряджання"</string>
- <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
- <skip />
- <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
- <skip />
+ <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Заряджання призупинено, щоб захистити акумулятор"</string>
+ <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Перевірте зарядний пристрій"</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"Мережу заблоковано"</string>
<string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Немає SIM-карти"</string>
<string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"Непридатна SIM-карта."</string>
diff --git a/packages/SystemUI/res-keyguard/values-ur/strings.xml b/packages/SystemUI/res-keyguard/values-ur/strings.xml
index 3c47dd5..e466807 100644
--- a/packages/SystemUI/res-keyguard/values-ur/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ur/strings.xml
@@ -33,10 +33,8 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • چارج ہو رہا ہے"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • تیزی سے چارج ہو رہا ہے"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • آہستہ چارج ہو رہا ہے"</string>
- <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
- <skip />
- <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
- <skip />
+ <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • بیٹری کی حفاظت کرنے کے لیے چارجنگ ہولڈ پر ہے"</string>
+ <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • چارجنگ ایکسیسری چیک کریں"</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"نیٹ ورک مقفل ہو گیا"</string>
<string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"کوئی SIM نہیں ہے"</string>
<string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"ناقابل استعمال SIM۔"</string>
diff --git a/packages/SystemUI/res-keyguard/values-uz/strings.xml b/packages/SystemUI/res-keyguard/values-uz/strings.xml
index f58628b..f3cdf26 100644
--- a/packages/SystemUI/res-keyguard/values-uz/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-uz/strings.xml
@@ -33,10 +33,8 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Quvvat olmoqda"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Tezkor quvvat olmoqda"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Sekin quvvat olmoqda"</string>
- <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
- <skip />
- <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
- <skip />
+ <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Batareyani himoyalash uchun quvvatlash toʻxtatildi"</string>
+ <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Quvvatlash aksessuarini tekshiring"</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"Tarmoq qulflangan"</string>
<string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"SIM kartasiz"</string>
<string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"Ishlamaydigan SIM."</string>
diff --git a/packages/SystemUI/res-keyguard/values-vi/strings.xml b/packages/SystemUI/res-keyguard/values-vi/strings.xml
index 7fb272f..3bad8f1 100644
--- a/packages/SystemUI/res-keyguard/values-vi/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-vi/strings.xml
@@ -33,10 +33,8 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Đang sạc"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Đang sạc nhanh"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Đang sạc chậm"</string>
- <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
- <skip />
- <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
- <skip />
+ <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Đang tạm ngưng sạc để bảo vệ pin"</string>
+ <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Hãy kiểm tra phụ kiện sạc"</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"Mạng đã bị khóa"</string>
<string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Không có SIM"</string>
<string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"SIM không sử dụng được."</string>
diff --git a/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml b/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml
index 79e00fd..2818ffb 100644
--- a/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml
@@ -33,10 +33,8 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • 正在充电"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • 正在快速充电"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • 正在慢速充电"</string>
- <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
- <skip />
- <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
- <skip />
+ <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • 为保护电池,充电已暂停"</string>
+ <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • 请检查充电配件"</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"网络已锁定"</string>
<string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"没有 SIM 卡"</string>
<string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"SIM 卡无法使用。"</string>
diff --git a/packages/SystemUI/res-keyguard/values-zh-rHK/strings.xml b/packages/SystemUI/res-keyguard/values-zh-rHK/strings.xml
index 76f366a..1b196d4 100644
--- a/packages/SystemUI/res-keyguard/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-zh-rHK/strings.xml
@@ -33,10 +33,8 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • 正在充電"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • 快速充電中"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • 慢速充電中"</string>
- <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
- <skip />
- <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
- <skip />
+ <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> - 為保護電池,目前暫停充電"</string>
+ <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • 檢查充電配件"</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"網絡已鎖定"</string>
<string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"沒有 SIM 卡"</string>
<string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"SIM 卡無法使用。"</string>
diff --git a/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml b/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml
index e7e25c1..9b7e431 100644
--- a/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml
@@ -33,10 +33,8 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • 充電中"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • 快速充電中"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • 慢速充電中"</string>
- <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
- <skip />
- <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
- <skip />
+ <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • 為保護電池,目前暫停充電"</string>
+ <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • 請檢查充電配件"</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"網路已鎖定"</string>
<string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"沒有 SIM 卡"</string>
<string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"SIM 卡無法使用。"</string>
diff --git a/packages/SystemUI/res-keyguard/values-zu/strings.xml b/packages/SystemUI/res-keyguard/values-zu/strings.xml
index 61f956a..cd36f95 100644
--- a/packages/SystemUI/res-keyguard/values-zu/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-zu/strings.xml
@@ -33,10 +33,8 @@
<string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Iyashaja"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Ishaja kaningi"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Ishaja kancane"</string>
- <!-- no translation found for keyguard_plugged_in_charging_limited (5369697538556777542) -->
- <skip />
- <!-- no translation found for keyguard_plugged_in_incompatible_charger (6384203333154532125) -->
- <skip />
+ <string name="keyguard_plugged_in_charging_limited" msgid="5369697538556777542">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Ukushaja kumisiwe ukuze kuvikelwe ibhethri"</string>
+ <string name="keyguard_plugged_in_incompatible_charger" msgid="6384203333154532125">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Hlola insiza yokushaja"</string>
<string name="keyguard_network_locked_message" msgid="407096292844868608">"Inethiwekhi ivaliwe"</string>
<string name="keyguard_missing_sim_message_short" msgid="685029586173458728">"Ayikho i-SIM"</string>
<string name="keyguard_permanent_disabled_sim_message_short" msgid="3955052454216046100">"I-SIM engasebenziseki."</string>
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 30ac963..32ea2ce 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -418,6 +418,10 @@
<string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Voeg by, verwyder en herrangskik jou legstukke in hierdie spasie"</string>
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Voeg meer legstukke by"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Langdruk om legstukke te pasmaak"</string>
+ <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+ <skip />
+ <!-- no translation found for edit_widget (9030848101135393954) -->
+ <skip />
<string name="button_to_remove_widget" msgid="3948204829181214098">"Verwyder"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Voeg legstuk by"</string>
<string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Klaar"</string>
@@ -1213,7 +1217,8 @@
<string name="assistant_attention_content_description" msgid="4166330881435263596">"Gebruikerteenwoordigheid is bespeur"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Stel versteknotasapp in Instellings"</string>
<string name="install_app" msgid="5066668100199613936">"Installeer app"</string>
- <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Swiep om voort te gaan"</string>
+ <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+ <skip />
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Sinkroniseer wedersyds na eksterne skerm?"</string>
<string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Jou binneste skerm sal weerspieël word. Jou boonste skerm sal afgeskakel word."</string>
<string name="mirror_display" msgid="2515262008898122928">"Sinkroniseer skerm wedersyds"</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 9aa6a18..12bca7d 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -418,6 +418,10 @@
<string name="cta_label_to_edit_widget" msgid="6496885074209203756">"በዚህ ቦታ ላይ የእርስዎን ምግብሮች ያክሉ፣ ያስወግዱ እና እንደገና ቅደም ተከተል ያስይዙ"</string>
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"ተጨማሪ ምግብሮችን ያክሉ"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"ምግብሮችን ለማበጀት በረጅሙ ይጫኑ"</string>
+ <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+ <skip />
+ <!-- no translation found for edit_widget (9030848101135393954) -->
+ <skip />
<string name="button_to_remove_widget" msgid="3948204829181214098">"አስወግድ"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"ምግብር አክል"</string>
<string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"ተከናውኗል"</string>
@@ -1213,7 +1217,8 @@
<string name="assistant_attention_content_description" msgid="4166330881435263596">"የተጠቃሚ ተገኝነት ታውቋል"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"በቅንብሮች ውስጥ ነባሪ የማስታወሻዎች መተግበሪያን ያቀናብሩ"</string>
<string name="install_app" msgid="5066668100199613936">"መተግበሪያን ጫን"</string>
- <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"ለመቀጠል ያንሸራትቱ"</string>
+ <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+ <skip />
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"ወደ ውጫዊ ማሳያ ይንጸባረቅ?"</string>
<string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"የውስጥ ማሳያዎ ይንጸባረቃል። የፊት ማሳያዎ ይጠፋል።"</string>
<string name="mirror_display" msgid="2515262008898122928">"ማሳያን አንጸባርቅ"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 0874ffb..1101e20 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -418,6 +418,10 @@
<string name="cta_label_to_edit_widget" msgid="6496885074209203756">"يمكنك في هذه المساحة إضافة التطبيقات المصغّرة وإزالتها وإعادة ترتيبها."</string>
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"إضافة المزيد من التطبيقات المصغّرة"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"اضغط مع الاستمرار لتخصيص التطبيقات المصغّرة."</string>
+ <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+ <skip />
+ <!-- no translation found for edit_widget (9030848101135393954) -->
+ <skip />
<string name="button_to_remove_widget" msgid="3948204829181214098">"إزالة"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"إضافة تطبيق مصغّر"</string>
<string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"تم"</string>
@@ -1213,7 +1217,8 @@
<string name="assistant_attention_content_description" msgid="4166330881435263596">"تم رصد تواجد المستخدم."</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"يمكنك ضبط تطبيق تدوين الملاحظات التلقائي في \"الإعدادات\"."</string>
<string name="install_app" msgid="5066668100199613936">"تثبيت التطبيق"</string>
- <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"مرِّر سريعًا للمتابعة."</string>
+ <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+ <skip />
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"هل تريد بث محتوى جهازك على الشاشة الخارجية؟"</string>
<string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"سيتم النسخ المطابق لمحتوى الشاشة الداخلية، وإيقاف الشاشة الأمامية."</string>
<string name="mirror_display" msgid="2515262008898122928">"بث المحتوى على الشاشة"</string>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index 0338188..3050685 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -418,6 +418,10 @@
<string name="cta_label_to_edit_widget" msgid="6496885074209203756">"এই স্পেচটোত আপোনাৰ ৱিজেটসমূহ যোগ দিয়ক, আঁতৰাওক আৰু সেইসমূহৰ ক্ৰম সলনি কৰক"</string>
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"অধিক ৱিজেট যোগ দিয়ক"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"ৱিজেট কাষ্টমাইজ কৰিবলৈ দীঘলীয়াকৈ টিপক"</string>
+ <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+ <skip />
+ <!-- no translation found for edit_widget (9030848101135393954) -->
+ <skip />
<string name="button_to_remove_widget" msgid="3948204829181214098">"আঁতৰাওক"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"ৱিজেট যোগ দিয়ক"</string>
<string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"কৰা হ’ল"</string>
@@ -1213,7 +1217,8 @@
<string name="assistant_attention_content_description" msgid="4166330881435263596">"ব্যৱহাৰকাৰীৰ উপস্থিতি চিনাক্ত কৰা হৈছে"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"ছেটিঙত টোকাৰ ডিফ’ল্ট এপ্ ছেট কৰক"</string>
<string name="install_app" msgid="5066668100199613936">"এপ্টো ইনষ্টল কৰক"</string>
- <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"অব্যাহত ৰাখিবলৈ ছোৱাইপ কৰক"</string>
+ <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+ <skip />
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"বাহ্যিক ডিছপ্লে’লৈ মিৰ’ৰ কৰিবনে?"</string>
<string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"আপোনাৰ ইনাৰ ডিছপ্লে’ প্ৰতিবিম্বিত কৰা হ’ব। আপোনাৰ ফ্ৰণ্ট ডিছপ্লে’ অফ কৰা হ’ব।"</string>
<string name="mirror_display" msgid="2515262008898122928">"ডিছপ্লে’ মিৰ’ৰ কৰক"</string>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index c858c3b..3c3462b 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -418,6 +418,10 @@
<string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Burada vidcetlər əlavə edin, silin və sırasını dəyişin"</string>
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Vidcetlər əlavə edin"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Basıb saxlayaraq vidcetləri fərdiləşdirin"</string>
+ <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+ <skip />
+ <!-- no translation found for edit_widget (9030848101135393954) -->
+ <skip />
<string name="button_to_remove_widget" msgid="3948204829181214098">"Silin"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Vidcet əlavə edin"</string>
<string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Hazırdır"</string>
@@ -1213,7 +1217,8 @@
<string name="assistant_attention_content_description" msgid="4166330881435263596">"İstifadəçi mövcudluğu aşkarlandı"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Ayarlarda defolt qeydlər tətbiqi ayarlayın"</string>
<string name="install_app" msgid="5066668100199613936">"Tətbiqi quraşdırın"</string>
- <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Çəkərək davam edin"</string>
+ <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+ <skip />
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Xarici displeyə əks etdirilsin?"</string>
<string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"İç displey əks etdiriləcək. Ön ekran deaktiv ediləcək."</string>
<string name="mirror_display" msgid="2515262008898122928">"Displeyi əks etdirin"</string>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index 379c68e..33e7921 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -418,6 +418,10 @@
<string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Dodajte, uklonite i preuredite vidžete u ovom prostoru"</string>
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Dodajte još vidžeta"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Dugi pritisak za prilagođavanje vidžeta"</string>
+ <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+ <skip />
+ <!-- no translation found for edit_widget (9030848101135393954) -->
+ <skip />
<string name="button_to_remove_widget" msgid="3948204829181214098">"Ukloni"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Dodaj vidžet"</string>
<string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Gotovo"</string>
@@ -1213,7 +1217,8 @@
<string name="assistant_attention_content_description" msgid="4166330881435263596">"Prisustvo korisnika može da se otkrije"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Podesite podrazumevanu aplikaciju za beleške u Podešavanjima"</string>
<string name="install_app" msgid="5066668100199613936">"Instaliraj aplikaciju"</string>
- <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Prevucite da biste nastavili"</string>
+ <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+ <skip />
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Želite li da preslikate na spoljnji ekran?"</string>
<string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Unutrašnji ekran će se preslikati. Prednji ekran će se isključiti."</string>
<string name="mirror_display" msgid="2515262008898122928">"Preslikaj ekran"</string>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index 97e8f17..b7e3b1b 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -418,6 +418,10 @@
<string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Дадаць ці выдаліць віджэты ў гэтай вобласці або змяніць іх парадак"</string>
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Дадаць іншыя віджэты"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Доўга націскайце, каб наладзіць віджэты"</string>
+ <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+ <skip />
+ <!-- no translation found for edit_widget (9030848101135393954) -->
+ <skip />
<string name="button_to_remove_widget" msgid="3948204829181214098">"Выдаліць"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Дадаць віджэт"</string>
<string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Гатова"</string>
@@ -1213,7 +1217,8 @@
<string name="assistant_attention_content_description" msgid="4166330881435263596">"Выяўлена прысутнасць карыстальніка"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Задайце ў Наладах стандартную праграму для нататак"</string>
<string name="install_app" msgid="5066668100199613936">"Усталяваць праграму"</string>
- <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Правядзіце пальцам, каб працягнуць"</string>
+ <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+ <skip />
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Адлюстраваць на знешнім дысплэі?"</string>
<string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Будзе ўключана дубліраванне ўнутранага дысплэя. Пярэдні дысплэй будзе выключаны."</string>
<string name="mirror_display" msgid="2515262008898122928">"Адлюстраваць дысплэй"</string>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index f8585bc..c1a27d2 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -418,6 +418,10 @@
<string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Добавяйте, премахвайте и пренареждайте приспособленията си в тази област"</string>
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Добавете още приспособления"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Натиснете продължително за персонализ. на приспос."</string>
+ <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+ <skip />
+ <!-- no translation found for edit_widget (9030848101135393954) -->
+ <skip />
<string name="button_to_remove_widget" msgid="3948204829181214098">"Премахване"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Добавяне на приспособление"</string>
<string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Готово"</string>
@@ -1213,7 +1217,8 @@
<string name="assistant_attention_content_description" msgid="4166330881435263596">"Установено е присъствие на потребител"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Задайте стандартно приложение за бележки от настройките"</string>
<string name="install_app" msgid="5066668100199613936">"Инсталиране на приложението"</string>
- <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Прекарайте пръст, за да продължите"</string>
+ <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+ <skip />
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Да се дублира ли на външния екран?"</string>
<string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Съдържанието на вътрешния ви дисплей ще бъде дублирано. Предният ви дисплей ще бъде изключен."</string>
<string name="mirror_display" msgid="2515262008898122928">"Дублиране на дисплея"</string>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index 2229e8f..a694f5e 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -418,6 +418,10 @@
<string name="cta_label_to_edit_widget" msgid="6496885074209203756">"এই স্পেসে আপনার উইজেট যোগ করুন, সরান ও আবার সাজান"</string>
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"আরও উইজেট যোগ করুন"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"উইজেট কাস্টমাইজ করতে বেশিক্ষণ প্রেস করুন"</string>
+ <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+ <skip />
+ <!-- no translation found for edit_widget (9030848101135393954) -->
+ <skip />
<string name="button_to_remove_widget" msgid="3948204829181214098">"সরান"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"উইজেট যোগ করুন"</string>
<string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"হয়ে গেছে"</string>
@@ -1213,7 +1217,8 @@
<string name="assistant_attention_content_description" msgid="4166330881435263596">"ব্যবহারকারীর উপস্থিতি শনাক্ত করা হয়েছে"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"\'সেটিংস\' থেকে ডিফল্ট নোট নেওয়ার অ্যাপ সেট করুন"</string>
<string name="install_app" msgid="5066668100199613936">"অ্যাপ ইনস্টল করুন"</string>
- <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"চালিয়ে যেতে সোয়াইপ করুন"</string>
+ <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+ <skip />
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"এক্সটার্নাল ডিসপ্লেতে মিরর করবেন?"</string>
<string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"আপনার ইনার ডিসপ্লে মিরর করা হবে। আপনার ফ্রন্ট ডিসপ্লে বন্ধ করা হবে।"</string>
<string name="mirror_display" msgid="2515262008898122928">"ডিসপ্লে দেখান"</string>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index d704b0a..1c7198a 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -418,6 +418,10 @@
<string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Dodajte, uklonite i promijenite raspored vidžeta u ovom prostoru"</string>
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Dodajte još vidžeta"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Pritisnite i zadržite da prilagodite vidžete"</string>
+ <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+ <skip />
+ <!-- no translation found for edit_widget (9030848101135393954) -->
+ <skip />
<string name="button_to_remove_widget" msgid="3948204829181214098">"Uklanjanje"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Dodajte vidžet"</string>
<string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Gotovo"</string>
@@ -1213,7 +1217,8 @@
<string name="assistant_attention_content_description" msgid="4166330881435263596">"Otkriveno je prisustvo korisnika"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Postavite zadanu aplikaciju za bilješke u Postavkama"</string>
<string name="install_app" msgid="5066668100199613936">"Instaliraj aplikaciju"</string>
- <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Prevucite da nastavite"</string>
+ <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+ <skip />
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Preslikati na vanjski ekran?"</string>
<string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Unutrašnji ekran će se preslikavati. Prednji ekran će se isključiti."</string>
<string name="mirror_display" msgid="2515262008898122928">"Preslikaj ekran"</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index ab3bc8f..948fb5c 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -418,6 +418,10 @@
<string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Afegeix, suprimeix i reordena widgets en aquest espai"</string>
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Afegeix més widgets"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Mantén premut per personalitzar els widgets"</string>
+ <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+ <skip />
+ <!-- no translation found for edit_widget (9030848101135393954) -->
+ <skip />
<string name="button_to_remove_widget" msgid="3948204829181214098">"Suprimeix"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Afegeix un widget"</string>
<string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Fet"</string>
@@ -1213,7 +1217,8 @@
<string name="assistant_attention_content_description" msgid="4166330881435263596">"S\'ha detectat la presència d\'usuaris"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Defineix l\'aplicació de notes predeterminada a Configuració"</string>
<string name="install_app" msgid="5066668100199613936">"Instal·la l\'aplicació"</string>
- <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Llisca per continuar"</string>
+ <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+ <skip />
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Duplicar a la pantalla externa?"</string>
<string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"La pantalla interior es duplicarà. La pantalla frontal es desactivarà."</string>
<string name="mirror_display" msgid="2515262008898122928">"Duplica la pantalla"</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 4dd9d4f..33397fe 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -418,6 +418,10 @@
<string name="cta_label_to_edit_widget" msgid="6496885074209203756">"V tomto prostoru můžete přidávat a odstraňovat widgety a měnit jejich pořadí"</string>
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Přidat další widgety"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Dlouhým stisknutím můžete přizpůsobit widgety"</string>
+ <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+ <skip />
+ <!-- no translation found for edit_widget (9030848101135393954) -->
+ <skip />
<string name="button_to_remove_widget" msgid="3948204829181214098">"Odstranit"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Přidat widget"</string>
<string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Hotovo"</string>
@@ -1213,7 +1217,8 @@
<string name="assistant_attention_content_description" msgid="4166330881435263596">"Je zjištěna přítomnost uživatele"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Výchozí aplikaci pro poznámky nastavíte v Nastavení"</string>
<string name="install_app" msgid="5066668100199613936">"Nainstalovat aplikaci"</string>
- <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Pokračujte přejetím prstem"</string>
+ <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+ <skip />
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Zrcadlit na externí displej?"</string>
<string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Vnitřní displej bude zrcadlen. Přední displej bude vypnutý."</string>
<string name="mirror_display" msgid="2515262008898122928">"Zrcadlit displej"</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index a2d17df..35142da 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -418,6 +418,10 @@
<string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Tilføj, fjern og omorganiser widgets i dette rum"</string>
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Tilføj flere widgets"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Hold fingeren nede for at tilpasse widgets"</string>
+ <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+ <skip />
+ <!-- no translation found for edit_widget (9030848101135393954) -->
+ <skip />
<string name="button_to_remove_widget" msgid="3948204829181214098">"Fjern"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Tilføj widget"</string>
<string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Udfør"</string>
@@ -1213,7 +1217,8 @@
<string name="assistant_attention_content_description" msgid="4166330881435263596">"Brugertilstedeværelse er registreret"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Angiv standardapp til noter i Indstillinger"</string>
<string name="install_app" msgid="5066668100199613936">"Installer app"</string>
- <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Stryg for at fortsætte"</string>
+ <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+ <skip />
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Vil du spejle til ekstern skærm?"</string>
<string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Din indre skærm spejles. Din skærm på forsiden slukkes."</string>
<string name="mirror_display" msgid="2515262008898122928">"Spejl skærm"</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index bebedce..e100b90 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -418,6 +418,10 @@
<string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Hier kannst du Widgets hinzufügen, entfernen und neu anordnen"</string>
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Weitere Widgets hinzufügen"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Lange drücken, um Widgets anzupassen"</string>
+ <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+ <skip />
+ <!-- no translation found for edit_widget (9030848101135393954) -->
+ <skip />
<string name="button_to_remove_widget" msgid="3948204829181214098">"Entfernen"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Widget hinzufügen"</string>
<string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Fertig"</string>
@@ -1213,7 +1217,8 @@
<string name="assistant_attention_content_description" msgid="4166330881435263596">"Anwesenheit des Nutzers wurde erkannt"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Standard-Notizen-App in den Einstellungen einrichten"</string>
<string name="install_app" msgid="5066668100199613936">"App installieren"</string>
- <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Zum Fortfahren wischen"</string>
+ <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+ <skip />
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Auf externen Bildschirm spiegeln?"</string>
<string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Dein inneres Display wird gespiegelt. Das Frontdisplay wird ausgeschaltet."</string>
<string name="mirror_display" msgid="2515262008898122928">"Bildschirm spiegeln"</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 3c87ad9..ed3a678 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -418,6 +418,10 @@
<string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Προσθήκη, κατάργηση και αναδιάταξη των γραφικών στοιχείων σε αυτόν τον χώρο"</string>
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Προσθήκη περισσότερων γραφικών στοιχείων"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Παρατεταμένο πάτημα για προσαρμογή γραφ. στοιχείων"</string>
+ <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+ <skip />
+ <!-- no translation found for edit_widget (9030848101135393954) -->
+ <skip />
<string name="button_to_remove_widget" msgid="3948204829181214098">"Κατάργηση"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Προσθήκη γραφικού στοιχείου"</string>
<string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Τέλος"</string>
@@ -1213,7 +1217,8 @@
<string name="assistant_attention_content_description" msgid="4166330881435263596">"Εντοπίστηκε παρουσία χρήστη"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Ορίστε την προεπιλεγμένη εφαρμογή σημειώσεων στις Ρυθμίσεις"</string>
<string name="install_app" msgid="5066668100199613936">"Εγκατάσταση εφαρμογής"</string>
- <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Σύρετε για συνέχεια"</string>
+ <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+ <skip />
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Κατοπτρισμός σε εξωτερική οθόνη;"</string>
<string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Θα γίνει κατοπτρισμός της εσωτερικής προβολής. Η μπροστινή οθόνη θα απενεργοποιηθεί."</string>
<string name="mirror_display" msgid="2515262008898122928">"Κατοπτρισμός οθόνης"</string>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index cbdc26f..31b4b6e 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -418,6 +418,10 @@
<string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Add, remove and reorder your widgets in this space"</string>
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Add more widgets"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Long press to customise widgets"</string>
+ <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+ <skip />
+ <!-- no translation found for edit_widget (9030848101135393954) -->
+ <skip />
<string name="button_to_remove_widget" msgid="3948204829181214098">"Remove"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Add widget"</string>
<string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Done"</string>
@@ -1213,7 +1217,8 @@
<string name="assistant_attention_content_description" msgid="4166330881435263596">"User presence is detected"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Set default notes app in Settings"</string>
<string name="install_app" msgid="5066668100199613936">"Install app"</string>
- <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Swipe to continue"</string>
+ <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+ <skip />
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Mirror to external display?"</string>
<string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Your inner display will be mirrored. Your front display will be turned off."</string>
<string name="mirror_display" msgid="2515262008898122928">"Mirror display"</string>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index da14f53..23cd700 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -418,6 +418,9 @@
<string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Add, remove, and reorder your widgets in this space"</string>
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Add more widgets"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Long press to customize widgets"</string>
+ <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+ <skip />
+ <string name="edit_widget" msgid="9030848101135393954">"Edit widget"</string>
<string name="button_to_remove_widget" msgid="3948204829181214098">"Remove"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Add widget"</string>
<string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Done"</string>
@@ -1213,7 +1216,7 @@
<string name="assistant_attention_content_description" msgid="4166330881435263596">"User presence is detected"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Set default notes app in Settings"</string>
<string name="install_app" msgid="5066668100199613936">"Install app"</string>
- <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Swipe to continue"</string>
+ <string name="dismissible_keyguard_swipe" msgid="8377597870094949432">"Swipe up to continue"</string>
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Mirror to external display?"</string>
<string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Your inner display will be mirrored. Your front display will be turned off."</string>
<string name="mirror_display" msgid="2515262008898122928">"Mirror display"</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index cbdc26f..31b4b6e 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -418,6 +418,10 @@
<string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Add, remove and reorder your widgets in this space"</string>
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Add more widgets"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Long press to customise widgets"</string>
+ <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+ <skip />
+ <!-- no translation found for edit_widget (9030848101135393954) -->
+ <skip />
<string name="button_to_remove_widget" msgid="3948204829181214098">"Remove"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Add widget"</string>
<string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Done"</string>
@@ -1213,7 +1217,8 @@
<string name="assistant_attention_content_description" msgid="4166330881435263596">"User presence is detected"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Set default notes app in Settings"</string>
<string name="install_app" msgid="5066668100199613936">"Install app"</string>
- <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Swipe to continue"</string>
+ <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+ <skip />
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Mirror to external display?"</string>
<string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Your inner display will be mirrored. Your front display will be turned off."</string>
<string name="mirror_display" msgid="2515262008898122928">"Mirror display"</string>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index cbdc26f..31b4b6e 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -418,6 +418,10 @@
<string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Add, remove and reorder your widgets in this space"</string>
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Add more widgets"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Long press to customise widgets"</string>
+ <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+ <skip />
+ <!-- no translation found for edit_widget (9030848101135393954) -->
+ <skip />
<string name="button_to_remove_widget" msgid="3948204829181214098">"Remove"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Add widget"</string>
<string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Done"</string>
@@ -1213,7 +1217,8 @@
<string name="assistant_attention_content_description" msgid="4166330881435263596">"User presence is detected"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Set default notes app in Settings"</string>
<string name="install_app" msgid="5066668100199613936">"Install app"</string>
- <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Swipe to continue"</string>
+ <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+ <skip />
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Mirror to external display?"</string>
<string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Your inner display will be mirrored. Your front display will be turned off."</string>
<string name="mirror_display" msgid="2515262008898122928">"Mirror display"</string>
diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml
index aec29d8..2970880 100644
--- a/packages/SystemUI/res/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings.xml
@@ -418,6 +418,9 @@
<string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Add, remove, and reorder your widgets in this space"</string>
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Add more widgets"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Long press to customize widgets"</string>
+ <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+ <skip />
+ <string name="edit_widget" msgid="9030848101135393954">"Edit widget"</string>
<string name="button_to_remove_widget" msgid="3948204829181214098">"Remove"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Add widget"</string>
<string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Done"</string>
@@ -1213,7 +1216,7 @@
<string name="assistant_attention_content_description" msgid="4166330881435263596">"User presence is detected"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Set default notes app in Settings"</string>
<string name="install_app" msgid="5066668100199613936">"Install app"</string>
- <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Swipe to continue"</string>
+ <string name="dismissible_keyguard_swipe" msgid="8377597870094949432">"Swipe up to continue"</string>
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Mirror to external display?"</string>
<string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Your inner display will be mirrored. Your front display will be turned off."</string>
<string name="mirror_display" msgid="2515262008898122928">"Mirror display"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 6dcc40a..8f2d0e7 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -418,6 +418,10 @@
<string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Agrega, quita y reordena tus widgets en este espacio"</string>
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Agregar más widgets"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Mantén presionado para personalizar los widgets"</string>
+ <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+ <skip />
+ <!-- no translation found for edit_widget (9030848101135393954) -->
+ <skip />
<string name="button_to_remove_widget" msgid="3948204829181214098">"Quitar"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Agregar widget"</string>
<string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Listo"</string>
@@ -1213,7 +1217,8 @@
<string name="assistant_attention_content_description" msgid="4166330881435263596">"Se detectó la presencia del usuario"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Configura la app de notas predeterminada en Configuración"</string>
<string name="install_app" msgid="5066668100199613936">"Instalar app"</string>
- <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Desliza el dedo para continuar"</string>
+ <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+ <skip />
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"¿Quieres duplicar en la pantalla externa?"</string>
<string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Se duplicará la pantalla interior. Se apagará la pantalla frontal."</string>
<string name="mirror_display" msgid="2515262008898122928">"Duplicar pantalla"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index aecf5b1..7848e87 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -418,6 +418,10 @@
<string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Añade, elimina y reordena tus widgets en este espacio"</string>
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Añade más widgets"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Mantén pulsado para personalizar los widgets"</string>
+ <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+ <skip />
+ <!-- no translation found for edit_widget (9030848101135393954) -->
+ <skip />
<string name="button_to_remove_widget" msgid="3948204829181214098">"Quitar"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Añadir widget"</string>
<string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Hecho"</string>
@@ -1213,7 +1217,8 @@
<string name="assistant_attention_content_description" msgid="4166330881435263596">"Se ha detectado la presencia de usuarios"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Configura la aplicación de notas predeterminada en Ajustes"</string>
<string name="install_app" msgid="5066668100199613936">"Instalar aplicación"</string>
- <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Desliza para continuar"</string>
+ <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+ <skip />
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"¿Proyectar a pantalla externa?"</string>
<string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Se proyectará tu pantalla interior. Se apagará tu pantalla frontal."</string>
<string name="mirror_display" msgid="2515262008898122928">"Proyectar pantalla"</string>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index edfb5be..6591799 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -418,6 +418,10 @@
<string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Lisage ja eemaldage selles ruumis oma vidinaid ning muutke nende järjestust"</string>
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Lisage rohkem vidinaid"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Vajutage pikalt vidinate kohandamiseks"</string>
+ <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+ <skip />
+ <!-- no translation found for edit_widget (9030848101135393954) -->
+ <skip />
<string name="button_to_remove_widget" msgid="3948204829181214098">"Eemalda"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Lisa vidin"</string>
<string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Valmis"</string>
@@ -1213,7 +1217,8 @@
<string name="assistant_attention_content_description" msgid="4166330881435263596">"Tuvastati kasutaja kohalolu"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Määrake seadetes märkmete vaikerakendus."</string>
<string name="install_app" msgid="5066668100199613936">"Installi rakendus"</string>
- <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Pühkige jätkamiseks"</string>
+ <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+ <skip />
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Kas peegeldada välisekraanile?"</string>
<string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Teie siseekraani peegeldatakse. Teie esiekraan lülitatakse välja."</string>
<string name="mirror_display" msgid="2515262008898122928">"Peegelda ekraani"</string>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index 7fe37b4..937aa24 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -366,8 +366,8 @@
<string name="sensor_privacy_mic_unblocked_dialog_content" msgid="4889961886199270224">"Aplikazio eta zerbitzu guztiek mikrofonoa erabil dezakete."</string>
<string name="sensor_privacy_mic_blocked_no_exception_dialog_content" msgid="5864898470772965394">"Mikrofonoa erabiltzeko baimena desgaituta dago aplikazio eta zerbitzu guztietarako. Mikrofonoa erabiltzeko baimena gaitzeko, joan Ezarpenak > Pribatutasuna > Mikrofonoa atalera."</string>
<string name="sensor_privacy_mic_blocked_with_exception_dialog_content" msgid="810289713700437896">"Mikrofonoa erabiltzeko baimena desgaituta dago aplikazio eta zerbitzu guztietarako. Baimen hori aldatzeko, joan Ezarpenak > Pribatutasuna > Mikrofonoa atalera."</string>
- <string name="sensor_privacy_camera_turned_on_dialog_title" msgid="8039095295100075952">"Piztu da kamera"</string>
- <string name="sensor_privacy_camera_turned_off_dialog_title" msgid="1936603903120742696">"Itzali da kamera"</string>
+ <string name="sensor_privacy_camera_turned_on_dialog_title" msgid="8039095295100075952">"Aktibatu da kamera"</string>
+ <string name="sensor_privacy_camera_turned_off_dialog_title" msgid="1936603903120742696">"Desaktibatu da kamera"</string>
<string name="sensor_privacy_camera_unblocked_dialog_content" msgid="7847190103011782278">"Aplikazio eta zerbitzu guztiek kamera erabil dezakete."</string>
<string name="sensor_privacy_camera_blocked_dialog_content" msgid="3182428709314874616">"Kamera erabiltzeko baimena desgaituta dago aplikazio eta zerbitzu guztietarako."</string>
<string name="sensor_privacy_htt_blocked_dialog_content" msgid="3333321592997666441">"Mikrofonoaren botoia erabiltzeko, gaitu mikrofonoa erabiltzeko baimena ezarpenetan."</string>
@@ -418,6 +418,10 @@
<string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Gehitu eta kendu eremu honetako widgetak, edo aldatu haien ordena"</string>
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Gehitu widget gehiago"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Widgetak pertsonalizatzeko, sakatu luze"</string>
+ <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+ <skip />
+ <!-- no translation found for edit_widget (9030848101135393954) -->
+ <skip />
<string name="button_to_remove_widget" msgid="3948204829181214098">"Kendu"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Gehitu widget bat"</string>
<string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Eginda"</string>
@@ -1213,7 +1217,8 @@
<string name="assistant_attention_content_description" msgid="4166330881435263596">"Erabiltzailearen presentzia hauteman da"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Ezarri oharren aplikazio lehenetsia ezarpenetan"</string>
<string name="install_app" msgid="5066668100199613936">"Instalatu aplikazioa"</string>
- <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Aurrera egiteko, pasatu hatza"</string>
+ <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+ <skip />
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Kanpoko pantailan islatu nahi duzu?"</string>
<string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Barneko pantaila islatuko da. Aurreko pantaila desaktibatu egingo da."</string>
<string name="mirror_display" msgid="2515262008898122928">"Islatu pantaila"</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 485009d..9948f5f 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -418,6 +418,10 @@
<string name="cta_label_to_edit_widget" msgid="6496885074209203756">"افزودن، برداشتن، و تغییر ترتیب ابزارکها در این فضا"</string>
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"افزودن ابزارکهای بیشتر"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"برای سفارشیسازی ابزارکها، فشار طولانی دهید"</string>
+ <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+ <skip />
+ <!-- no translation found for edit_widget (9030848101135393954) -->
+ <skip />
<string name="button_to_remove_widget" msgid="3948204829181214098">"برداشتن"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"افزودن ابزارک"</string>
<string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"تمام"</string>
@@ -1213,7 +1217,8 @@
<string name="assistant_attention_content_description" msgid="4166330881435263596">"حضور کاربر شناسایی میشود"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"برنامه پیشفرض یادداشت را در «تنظیمات» تنظیم کنید"</string>
<string name="install_app" msgid="5066668100199613936">"نصب برنامه"</string>
- <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"برای ادامه، تند بکشید"</string>
+ <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+ <skip />
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"روی نمایشگر خارجی قرینهسازی شود؟"</string>
<string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"نمایشگر داخلی شما قرینهسازی میشود. نمایشگر جلو خاموش میشود."</string>
<string name="mirror_display" msgid="2515262008898122928">"قرینهسازی نمایشگر"</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index e65d7e0..d4bb6bd 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -418,6 +418,10 @@
<string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Lisää, poista ja järjestä widgetejäsi uudelleen tässä tilassa"</string>
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Lisää widgetejä"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Yksilöi widgetit pitkällä painalluksella"</string>
+ <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+ <skip />
+ <!-- no translation found for edit_widget (9030848101135393954) -->
+ <skip />
<string name="button_to_remove_widget" msgid="3948204829181214098">"Poista"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Lisää widget"</string>
<string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Valmis"</string>
@@ -1213,7 +1217,8 @@
<string name="assistant_attention_content_description" msgid="4166330881435263596">"Käyttäjän läsnäolo havaittu"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Aseta oletusmuistiinpanosovellus Asetuksista"</string>
<string name="install_app" msgid="5066668100199613936">"Asenna sovellus"</string>
- <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Jatka pyyhkäisemällä"</string>
+ <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+ <skip />
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Peilataanko ulkoiselle näytölle?"</string>
<string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Sisänäyttö peilataan. Etunäyttö laitetaan pois päältä."</string>
<string name="mirror_display" msgid="2515262008898122928">"Peilaa näyttö"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 557b9b8..ea7b0b0 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -418,6 +418,10 @@
<string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Ajouter, retirer et réorganiser vos widgets dans cet espace"</string>
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Ajouter plus de widgets"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Maintenez le doigt pour personnaliser les widgets"</string>
+ <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+ <skip />
+ <!-- no translation found for edit_widget (9030848101135393954) -->
+ <skip />
<string name="button_to_remove_widget" msgid="3948204829181214098">"Retirer"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Ajouter un widget"</string>
<string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Terminé"</string>
@@ -1213,7 +1217,8 @@
<string name="assistant_attention_content_description" msgid="4166330881435263596">"La présence d\'un utilisateur est détectée"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Définir l\'application de prise de notes par défaut dans les Paramètres"</string>
<string name="install_app" msgid="5066668100199613936">"Installer l\'application"</string>
- <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Balayez l\'écran pour continuer"</string>
+ <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+ <skip />
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Dupliquer l\'écran sur un moniteur externe?"</string>
<string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Votre écran intérieur sera dupliqué. Votre écran frontal sera désactivé."</string>
<string name="mirror_display" msgid="2515262008898122928">"Dupliquer l\'écran"</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 13af9a5..acaa43e 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -418,6 +418,10 @@
<string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Dans cet espace, ajoutez, supprimez et réorganisez vos widgets"</string>
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Ajouter des widgets"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Appuyez de manière prolongée pour personnaliser les widgets"</string>
+ <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+ <skip />
+ <!-- no translation found for edit_widget (9030848101135393954) -->
+ <skip />
<string name="button_to_remove_widget" msgid="3948204829181214098">"Supprimer"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Ajouter un widget"</string>
<string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"OK"</string>
@@ -1213,7 +1217,8 @@
<string name="assistant_attention_content_description" msgid="4166330881435263596">"La présence de l\'utilisateur est détectée"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Définir une appli de notes par défaut dans les paramètres"</string>
<string name="install_app" msgid="5066668100199613936">"Installer l\'appli"</string>
- <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Balayer pour continuer"</string>
+ <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+ <skip />
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Dupliquer sur l\'écran externe ?"</string>
<string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Votre écran intérieur sera dupliqué. Votre écran frontal sera éteint."</string>
<string name="mirror_display" msgid="2515262008898122928">"Dupliquer l\'écran"</string>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index d30770d..6b23868 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -418,6 +418,10 @@
<string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Engadir, quitar e reordenar widgets neste espazo"</string>
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Engadir máis widgets"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Pulsación longa para personalizar os widgets"</string>
+ <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+ <skip />
+ <!-- no translation found for edit_widget (9030848101135393954) -->
+ <skip />
<string name="button_to_remove_widget" msgid="3948204829181214098">"Quitar"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Engadir widget"</string>
<string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Feito"</string>
@@ -1213,7 +1217,8 @@
<string name="assistant_attention_content_description" msgid="4166330881435263596">"Detectouse a presenza de usuarios"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Establece a aplicación de notas predeterminada en Configuración"</string>
<string name="install_app" msgid="5066668100199613936">"Instalar aplicación"</string>
- <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Pasa o dedo para continuar"</string>
+ <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+ <skip />
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Queres proxectar contido nunha pantalla externa?"</string>
<string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Proxectarase a pantalla interior. Desactivarase a pantalla frontal."</string>
<string name="mirror_display" msgid="2515262008898122928">"Proxectar pantalla"</string>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index 62ffdd3..6ea1f0e 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -418,6 +418,10 @@
<string name="cta_label_to_edit_widget" msgid="6496885074209203756">"આ સ્પેસમાં તમારા વિજેટ ઉમેરો, તેને કાઢી નાખો અને ફરી તેને ક્રમમાં ગોઠવો"</string>
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"વધુ વિજેટ ઉમેરો"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"વિજેટ કસ્ટમાઇઝ કરવા માટે થોડીવાર દબાવી રાખો"</string>
+ <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+ <skip />
+ <!-- no translation found for edit_widget (9030848101135393954) -->
+ <skip />
<string name="button_to_remove_widget" msgid="3948204829181214098">"કાઢી નાખો"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"વિજેટ ઉમેરો"</string>
<string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"થઈ ગયું"</string>
@@ -1213,7 +1217,8 @@
<string name="assistant_attention_content_description" msgid="4166330881435263596">"વપરાશકર્તાની હાજરીની ભાળ મળી છે"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"સેટિંગમાં નોંધની ડિફૉલ્ટ ઍપ સેટ કરો"</string>
<string name="install_app" msgid="5066668100199613936">"ઍપ ઇન્સ્ટૉલ કરો"</string>
- <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"ચાલુ રાખવા સ્વાઇપ કરો"</string>
+ <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+ <skip />
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"શું બાહ્ય ડિસ્પ્લે પર મિરર કરીએ?"</string>
<string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"તમારું ઇનર ડિસ્પ્લે મિરર કરવામાં આવશે. તમારું ફ્રન્ટ ડિસ્પ્લે બંધ કરવામાં આવશે."</string>
<string name="mirror_display" msgid="2515262008898122928">"મિરર ડિસ્પ્લે"</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 65cf5f7..db3549a 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -418,6 +418,10 @@
<string name="cta_label_to_edit_widget" msgid="6496885074209203756">"इस स्पेस में विजेट जोड़ें, हटाएं, और उन्हें फिर से क्रम में लगाएं"</string>
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"ज़्यादा विजेट जोड़ें"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"विजेट पसंद के मुताबिक बनाने के लिए उसे दबाकर रखें"</string>
+ <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+ <skip />
+ <!-- no translation found for edit_widget (9030848101135393954) -->
+ <skip />
<string name="button_to_remove_widget" msgid="3948204829181214098">"हटाएं"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"विजेट जोड़ें"</string>
<string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"हो गया"</string>
@@ -1213,7 +1217,8 @@
<string name="assistant_attention_content_description" msgid="4166330881435263596">"उपयोगकर्ता की मौजूदगी का पता लगाया गया"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"सेटिंग में जाकर, नोट लेने की सुविधा देने वाले ऐप्लिकेशन को डिफ़ॉल्ट के तौर पर सेट करें"</string>
<string name="install_app" msgid="5066668100199613936">"ऐप्लिकेशन इंस्टॉल करें"</string>
- <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"जारी रखने के लिए स्वाइप करें"</string>
+ <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+ <skip />
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"क्या आपको किसी बाहरी डिवाइस पर डिसप्ले करना है?"</string>
<string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"आपके फ़ोन के इनर डिसप्ले की स्क्रीन शेयर की जाएगी. फ़्रंट डिसप्ले को बंद कर दिया जाएगा."</string>
<string name="mirror_display" msgid="2515262008898122928">"डिसप्ले करें"</string>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index b502e85..27eb8e9 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -418,6 +418,10 @@
<string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Dodavanje, uklanjanje i promjena redoslijeda widgeta u ovom prostoru"</string>
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Dodavanje još widgeta"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Dugo pritisnite za prilagodbu widgeta"</string>
+ <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+ <skip />
+ <!-- no translation found for edit_widget (9030848101135393954) -->
+ <skip />
<string name="button_to_remove_widget" msgid="3948204829181214098">"Ukloni"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Dodaj widget"</string>
<string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Gotovo"</string>
@@ -1213,7 +1217,8 @@
<string name="assistant_attention_content_description" msgid="4166330881435263596">"Otkrivena je prisutnost korisnika"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Postavite zadanu aplikaciju za bilješke u postavkama"</string>
<string name="install_app" msgid="5066668100199613936">"Instalacija"</string>
- <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Prijeđite prstom za nastavak"</string>
+ <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+ <skip />
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Želite li zrcaliti na vanjski zaslon?"</string>
<string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Unutarnji zaslon bit će zrcaljen. Prednji zaslon bit će isključen."</string>
<string name="mirror_display" msgid="2515262008898122928">"Zrcaljenje zaslona"</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index c7ce0b5b..7a16d74 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -418,6 +418,10 @@
<string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Modulok hozzáadása, eltávolítása és átrendezése ezen a területen"</string>
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"További modulok hozzáadása"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Nyomja meg hosszan a modulok személyre szabásához"</string>
+ <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+ <skip />
+ <!-- no translation found for edit_widget (9030848101135393954) -->
+ <skip />
<string name="button_to_remove_widget" msgid="3948204829181214098">"Eltávolítás"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Modul hozzáadása"</string>
<string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Kész"</string>
@@ -1213,7 +1217,8 @@
<string name="assistant_attention_content_description" msgid="4166330881435263596">"Felhasználói jelenlét észlelve"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Állítson be alapértelmezett jegyzetkészítő alkalmazást a Beállításokban"</string>
<string name="install_app" msgid="5066668100199613936">"Alkalmazás telepítése"</string>
- <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Csúsztasson a folytatáshoz"</string>
+ <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+ <skip />
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Tükrözi a kijelzőt a külső képernyőre?"</string>
<string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"A belső kijelző tükrözve lesz. Az elülső kijelző ki lesz kapcsolva."</string>
<string name="mirror_display" msgid="2515262008898122928">"Kijelző tükrözése"</string>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index 7db84db..f3e883f 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -418,6 +418,10 @@
<string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Ավելացնել վիջեթներ, ինչպես նաև հեռացնել և վերադասավորել դրանք այս տարածքում"</string>
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Ավելացնել վիջեթներ"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Երկար սեղմեք՝ վիջեթները հարմարեցնելու համար"</string>
+ <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+ <skip />
+ <!-- no translation found for edit_widget (9030848101135393954) -->
+ <skip />
<string name="button_to_remove_widget" msgid="3948204829181214098">"Հեռացնել"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Ավելացնել վիջեթ"</string>
<string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Պատրաստ է"</string>
@@ -1213,7 +1217,8 @@
<string name="assistant_attention_content_description" msgid="4166330881435263596">"Հայտնաբերվել է օգտատեր"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Կարգավորեք նշումների կանխադրված հավելված Կարգավորումներում"</string>
<string name="install_app" msgid="5066668100199613936">"Տեղադրել հավելվածը"</string>
- <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Սահեցրեք շարունակելու համար"</string>
+ <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+ <skip />
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Հայելապատճենե՞լ արտաքին էկրանին"</string>
<string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Ներքին էկրանը կհայելապատճենվի։ Առջևի էկրանը կանջատվի։"</string>
<string name="mirror_display" msgid="2515262008898122928">"Հայելապատճենել էկրանը"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index b7e7e81..fdd111f 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -418,6 +418,10 @@
<string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Tambahkan, hapus, dan susun ulang widget Anda di ruang ini"</string>
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Tambahkan widget lainnya"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Tekan lama untuk menyesuaikan widget"</string>
+ <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+ <skip />
+ <!-- no translation found for edit_widget (9030848101135393954) -->
+ <skip />
<string name="button_to_remove_widget" msgid="3948204829181214098">"Hapus"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Tambahkan widget"</string>
<string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Selesai"</string>
@@ -1213,7 +1217,8 @@
<string name="assistant_attention_content_description" msgid="4166330881435263596">"Kehadiran pengguna terdeteksi"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Setel aplikasi catatan default di Setelan"</string>
<string name="install_app" msgid="5066668100199613936">"Instal aplikasi"</string>
- <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Geser untuk melanjutkan"</string>
+ <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+ <skip />
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Cerminkan ke layar eksternal?"</string>
<string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Layar dalam akan dicerminkan. Layar depan akan dinonaktifkan."</string>
<string name="mirror_display" msgid="2515262008898122928">"Cerminkan layar"</string>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index db1b743..cdbc055c 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -418,6 +418,10 @@
<string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Bættu við, fjarlægðu og endurraðaðu græjunum þínum í þessu rými"</string>
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Bæta við fleiri græjum"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Haltu inni til að sérsníða græjur"</string>
+ <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+ <skip />
+ <!-- no translation found for edit_widget (9030848101135393954) -->
+ <skip />
<string name="button_to_remove_widget" msgid="3948204829181214098">"Fjarlægja"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Bæta græju við"</string>
<string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Lokið"</string>
@@ -1213,7 +1217,8 @@
<string name="assistant_attention_content_description" msgid="4166330881435263596">"Viðvera notanda greindist"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Stilltu sjálfgefið glósuforrit í stillingunum"</string>
<string name="install_app" msgid="5066668100199613936">"Setja upp forrit"</string>
- <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Strjúktu til að halda áfram"</string>
+ <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+ <skip />
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Spegla yfir á ytri skjá?"</string>
<string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Innri skjárinn þinn verður speglaður. Slökkt verður á framskjánum þínum."</string>
<string name="mirror_display" msgid="2515262008898122928">"Spegla skjá"</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 997b76b..ec74e40 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -418,6 +418,10 @@
<string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Aggiungi, rimuovi e riordina i tuoi widget in questo spazio"</string>
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Aggiungi altri widget"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Premi a lungo per personalizzare i widget"</string>
+ <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+ <skip />
+ <!-- no translation found for edit_widget (9030848101135393954) -->
+ <skip />
<string name="button_to_remove_widget" msgid="3948204829181214098">"Rimuovi"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Aggiungi widget"</string>
<string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Fine"</string>
@@ -1213,7 +1217,8 @@
<string name="assistant_attention_content_description" msgid="4166330881435263596">"Viene rilevata la presenza dell\'utente"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Imposta l\'app per le note predefinita nelle Impostazioni"</string>
<string name="install_app" msgid="5066668100199613936">"Installa app"</string>
- <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Scorri per continuare"</string>
+ <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+ <skip />
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Vuoi eseguire il mirroring al display esterno?"</string>
<string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Verrà eseguito il mirroring del tuo display interno. Il tuo display frontale verrà spento."</string>
<string name="mirror_display" msgid="2515262008898122928">"Esegui il mirroring del display"</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 22079ac..ee1d0bd 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -418,6 +418,10 @@
<string name="cta_label_to_edit_widget" msgid="6496885074209203756">"הוספה, הסרה, וסידור מחדש של הווידג\'טים במרחב הזה"</string>
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"הוספת ווידג\'טים"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"לוחצים לחיצה ארוכה כדי להתאים אישית את הווידג\'טים"</string>
+ <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+ <skip />
+ <!-- no translation found for edit_widget (9030848101135393954) -->
+ <skip />
<string name="button_to_remove_widget" msgid="3948204829181214098">"הסרה"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"הוספת ווידג\'ט"</string>
<string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"סיום"</string>
@@ -1213,7 +1217,8 @@
<string name="assistant_attention_content_description" msgid="4166330881435263596">"נוכחות המשתמש זוהתה"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"צריך להגדיר את אפליקציית ברירת המחדל לפתקים ב\'הגדרות\'"</string>
<string name="install_app" msgid="5066668100199613936">"התקנת האפליקציה"</string>
- <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"צריך להחליק כדי להמשיך"</string>
+ <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+ <skip />
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"לשקף למסך חיצוני?"</string>
<string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"המסך הפנימי שלך ישוכפל. המסך החיצוני שלך יכובה."</string>
<string name="mirror_display" msgid="2515262008898122928">"תצוגת מראה"</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 74ccd50d..416a61d 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -418,6 +418,10 @@
<string name="cta_label_to_edit_widget" msgid="6496885074209203756">"このスペースでのウィジェットの追加、削除、並べ替え"</string>
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"ウィジェットの追加"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"長押ししてウィジェットをカスタマイズ"</string>
+ <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+ <skip />
+ <!-- no translation found for edit_widget (9030848101135393954) -->
+ <skip />
<string name="button_to_remove_widget" msgid="3948204829181214098">"削除"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"ウィジェットを追加"</string>
<string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"完了"</string>
@@ -1213,7 +1217,8 @@
<string name="assistant_attention_content_description" msgid="4166330881435263596">"会話を始められます"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"[設定] でデフォルトのメモアプリを設定してください"</string>
<string name="install_app" msgid="5066668100199613936">"アプリをインストール"</string>
- <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"スワイプして続行"</string>
+ <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+ <skip />
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"外部ディスプレイにミラーリングしますか?"</string>
<string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"インナー ディスプレイがミラーリングされます。フロント ディスプレイはオフになります。"</string>
<string name="mirror_display" msgid="2515262008898122928">"ディスプレイをミラーリングする"</string>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index 59d7487..db57e7e 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -418,6 +418,10 @@
<string name="cta_label_to_edit_widget" msgid="6496885074209203756">"ამ სივრცეში შეძლებთ თქვენი ვიჯეტების დამატებას, ამოშლასა და გადაწყობას"</string>
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"ვიჯეტების დამატება"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"ხანგრძლივად დააჭირეთ ვიჯეტების მოსარგებად"</string>
+ <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+ <skip />
+ <!-- no translation found for edit_widget (9030848101135393954) -->
+ <skip />
<string name="button_to_remove_widget" msgid="3948204829181214098">"ამოშლა"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"ვიჯეტის დამატება"</string>
<string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"მზადაა"</string>
@@ -1213,7 +1217,8 @@
<string name="assistant_attention_content_description" msgid="4166330881435263596">"აღმოჩენილია მომხმარებლის ყოფნა"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"დააყენეთ ნაგულისხმევი შენიშვნების აპი პარამეტრებში"</string>
<string name="install_app" msgid="5066668100199613936">"აპის ინსტალაცია"</string>
- <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"გადაფურცლეთ გასაგრძელებლად"</string>
+ <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+ <skip />
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"აირეკლოს გარე ეკრანზე?"</string>
<string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"თქვენი შიდა ეკრანი აირეკლება. თქვენი წინა ეკრანი გამოირთვება."</string>
<string name="mirror_display" msgid="2515262008898122928">"ეკრანის არეკვლა"</string>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index b6a18d79..a90c6e8 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -418,6 +418,10 @@
<string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Осы бөлмеде виджеттер қосыңыз, оларды өшіріңіз және ретін өзгертіңіз."</string>
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Басқа виджеттер қосыңыз."</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Виджеттерді бейімдеу үшін ұзақ басып тұрыңыз."</string>
+ <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+ <skip />
+ <!-- no translation found for edit_widget (9030848101135393954) -->
+ <skip />
<string name="button_to_remove_widget" msgid="3948204829181214098">"Өшіру"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Виджет қосу"</string>
<string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Дайын"</string>
@@ -1213,7 +1217,8 @@
<string name="assistant_attention_content_description" msgid="4166330881435263596">"Пайдаланушы анықталды."</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Параметрлерден әдепкі жазба қолданбасын орнатыңыз."</string>
<string name="install_app" msgid="5066668100199613936">"Қолданбаны орнату"</string>
- <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Жалғастыру үшін сырғытыңыз."</string>
+ <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+ <skip />
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Сыртқы экран арқылы да көрсету керек пе?"</string>
<string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Ішкі экран көшірмесі көрсетіледі. Алдыңғы экран өшіріледі."</string>
<string name="mirror_display" msgid="2515262008898122928">"Көрсету"</string>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index c2551e7..dfa26a5 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -418,6 +418,10 @@
<string name="cta_label_to_edit_widget" msgid="6496885074209203756">"បញ្ចូល ដកចេញ និងតម្រៀបធាតុក្រាហ្វិករបស់អ្នកឡើងវិញនៅក្នុងលំហនេះ"</string>
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"បញ្ចូលធាតុក្រាហ្វិកច្រើនទៀត"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"ចុចឱ្យយូរ ដើម្បីប្ដូរធាតុក្រាហ្វិកតាមបំណង"</string>
+ <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+ <skip />
+ <!-- no translation found for edit_widget (9030848101135393954) -->
+ <skip />
<string name="button_to_remove_widget" msgid="3948204829181214098">"ដកចេញ"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"បញ្ចូលធាតុក្រាហ្វិក"</string>
<string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"រួចរាល់"</string>
@@ -1213,7 +1217,8 @@
<string name="assistant_attention_content_description" msgid="4166330881435263596">"វត្តមានអ្នកប្រើប្រាស់ត្រូវបានចាប់ដឹង"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"កំណត់កម្មវិធីកំណត់ចំណាំលំនាំដើមនៅក្នុងការកំណត់"</string>
<string name="install_app" msgid="5066668100199613936">"ដំឡើងកម្មវិធី"</string>
- <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"សូមអូសដើម្បីបន្ត"</string>
+ <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+ <skip />
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"បញ្ចាំងទៅផ្ទាំងអេក្រង់ខាងក្រៅឬ?"</string>
<string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"អេក្រង់ខាងក្នុងរបស់អ្នកនឹងត្រូវបានធ្វើសមកាលកម្មទៅវិញទៅមក។ អេក្រង់មុខរបស់អ្នកនឹងត្រូវបានបិទ។"</string>
<string name="mirror_display" msgid="2515262008898122928">"បញ្ចាំងទៅផ្ទាំងអេក្រង់"</string>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index a04c95b..51d74cc 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -418,6 +418,10 @@
<string name="cta_label_to_edit_widget" msgid="6496885074209203756">"ಈ ಜಾಗದಲ್ಲಿ ನಿಮ್ಮ ವಿಜೆಟ್ಗಳನ್ನು ಸೇರಿಸಿ, ತೆಗೆದುಹಾಕಿ ಮತ್ತು ಮರುಕ್ರಮಗೊಳಿಸಿ"</string>
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"ಹೆಚ್ಚಿನ ವಿಜೆಟ್ಗಳನ್ನು ಸೇರಿಸಿ"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"ವಿಜೆಟ್ಗಳನ್ನು ಕಸ್ಟಮೈಸ್ ಮಾಡಲು ದೀರ್ಘಕಾಲ ಒತ್ತಿರಿ"</string>
+ <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+ <skip />
+ <!-- no translation found for edit_widget (9030848101135393954) -->
+ <skip />
<string name="button_to_remove_widget" msgid="3948204829181214098">"ತೆಗೆದುಹಾಕಿ"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"ವಿಜೆಟ್ ಅನ್ನು ಸೇರಿಸಿ"</string>
<string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"ಮುಗಿದಿದೆ"</string>
@@ -1213,7 +1217,8 @@
<string name="assistant_attention_content_description" msgid="4166330881435263596">"ಬಳಕೆದಾರರ ಉಪಸ್ಥಿತಿಯನ್ನು ಪತ್ತೆಹಚ್ಚಲಾಗಿದೆ"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"ಸೆಟ್ಟಿಂಗ್ಗಳಲ್ಲಿ ಡೀಫಾಲ್ಟ್ ಟಿಪ್ಪಣಿಗಳ ಆ್ಯಪ್ ಅನ್ನು ಸೆಟ್ ಮಾಡಿ"</string>
<string name="install_app" msgid="5066668100199613936">"ಆ್ಯಪ್ ಇನ್ಸ್ಟಾಲ್ ಮಾಡಿ"</string>
- <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"ಮುಂದುವರಿಯಲು ಸ್ವೈಪ್ ಮಾಡಿ"</string>
+ <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+ <skip />
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"ಬಾಹ್ಯ ಡಿಸ್ಪ್ಲೇಗೆ ಪ್ರತಿಬಿಂಬಿಸಬೇಕೆ?"</string>
<string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"ನಿಮ್ಮ ಒಳಗಿನ ಡಿಸ್ಪ್ಲೇ ಅನ್ನು ಪ್ರತಿಬಿಂಬಿಸಲಾಗುತ್ತದೆ. ನಿಮ್ಮ ಫ್ರಂಟ್ ಡಿಸ್ಪ್ಲೇ ಅನ್ನು ಆಫ್ ಮಾಡಲಾಗುತ್ತದೆ."</string>
<string name="mirror_display" msgid="2515262008898122928">"ಮಿರರ್ ಡಿಸ್ಪ್ಲೇ"</string>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index e199783..316fea7 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -418,6 +418,10 @@
<string name="cta_label_to_edit_widget" msgid="6496885074209203756">"이 공간에서 위젯 추가, 삭제 또는 다시 정렬"</string>
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"더 많은 위젯 추가"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"위젯을 맞춤설정하려면 길게 누르기"</string>
+ <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+ <skip />
+ <!-- no translation found for edit_widget (9030848101135393954) -->
+ <skip />
<string name="button_to_remove_widget" msgid="3948204829181214098">"삭제"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"위젯 추가"</string>
<string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"완료"</string>
@@ -1213,7 +1217,8 @@
<string name="assistant_attention_content_description" msgid="4166330881435263596">"사용자 정보가 감지되었습니다."</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"설정에서 기본 메모 앱 설정"</string>
<string name="install_app" msgid="5066668100199613936">"앱 설치"</string>
- <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"계속하려면 스와이프하세요"</string>
+ <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+ <skip />
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"외부 디스플레이로 미러링하시겠습니까?"</string>
<string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"내부 디스플레이가 미러링됩니다. 전면 디스플레이는 꺼집니다."</string>
<string name="mirror_display" msgid="2515262008898122928">"디스플레이 미러링"</string>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index e42dc71..d7b13a6 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -418,6 +418,10 @@
<string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Бул иш чөйрөсүнө виджеттерди кошуп, өчүрүп жана иретин өзгөртүңүз"</string>
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Көбүрөөк виджеттерди кошуу"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Виджеттерди ыңгайлаштыруу үчүн кое бербей басып туруңуз"</string>
+ <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+ <skip />
+ <!-- no translation found for edit_widget (9030848101135393954) -->
+ <skip />
<string name="button_to_remove_widget" msgid="3948204829181214098">"Өчүрүү"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Виджет кошуу"</string>
<string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Бүттү"</string>
@@ -1213,7 +1217,8 @@
<string name="assistant_attention_content_description" msgid="4166330881435263596">"Колдонуучу аныкталды"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Параметрлерден демейки кыска жазуулар колдонмосун тууралаңыз"</string>
<string name="install_app" msgid="5066668100199613936">"Колдонмону орнотуу"</string>
- <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Улантуу үчүн экранды сүрүп коюңуз"</string>
+ <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+ <skip />
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Тышкы экранга чыгарасызбы?"</string>
<string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Ички экраныңыз башка экранга чыгарылат. Алдыңкы экраныңыз өчүрүлөт."</string>
<string name="mirror_display" msgid="2515262008898122928">"Тышкы экран"</string>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index ea12242..1f0fbe4 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -418,6 +418,10 @@
<string name="cta_label_to_edit_widget" msgid="6496885074209203756">"ເພີ່ມ, ລຶບອອກ ແລະ ຈັດຮຽງວິດເຈັດຂອງທ່ານຄືນໃໝ່ໃນພື້ນທີ່ນີ້"</string>
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"ເພີ່ມວິດເຈັດເພີ່ມເຕີມ"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"ກົດຄ້າງໄວ້ເພື່ອປັບແຕ່ງວິດເຈັດ"</string>
+ <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+ <skip />
+ <!-- no translation found for edit_widget (9030848101135393954) -->
+ <skip />
<string name="button_to_remove_widget" msgid="3948204829181214098">"ລຶບອອກ"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"ເພີ່ມວິດເຈັດ"</string>
<string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"ແລ້ວໆ"</string>
@@ -1213,7 +1217,8 @@
<string name="assistant_attention_content_description" msgid="4166330881435263596">"ກວດພົບຕົວຕົນຜູ້ໃຊ້"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"ຕັ້ງຄ່າແອັບຈົດບັນທຶກເລີ່ມຕົ້ນໃນການຕັ້ງຄ່າ"</string>
<string name="install_app" msgid="5066668100199613936">"ຕິດຕັ້ງແອັບ"</string>
- <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"ປັດເພື່ອສືບຕໍ່"</string>
+ <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+ <skip />
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"ສາຍໃສ່ຈໍສະແດງຜົນພາຍນອກບໍ?"</string>
<string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"ການສະແດງຜົນທາງໃນຂອງທ່ານຈະຖືກສະທ້ອນ. ການສະແດງຜົນທາງໜ້າຂອງທ່ານຈະຖືກປິດໄວ້."</string>
<string name="mirror_display" msgid="2515262008898122928">"ຈໍສະແດງຜົນແບບສະທ້ອນ"</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 38a25e5..df88f0a 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -418,6 +418,10 @@
<string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Šioje erdvėje pridėkite valdiklių, juos pašalinkite ir keiskite jų tvarką"</string>
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Pridėkite daugiau valdiklių"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Ilgai paspauskite, kad tinkintumėte valdiklius"</string>
+ <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+ <skip />
+ <!-- no translation found for edit_widget (9030848101135393954) -->
+ <skip />
<string name="button_to_remove_widget" msgid="3948204829181214098">"Pašalinti"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Pridėti valdiklį"</string>
<string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Atlikta"</string>
@@ -1213,7 +1217,8 @@
<string name="assistant_attention_content_description" msgid="4166330881435263596">"Aptikta naudotojo veikla"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Nustatykite numatytąją užrašų programą Nustatymuose"</string>
<string name="install_app" msgid="5066668100199613936">"Įdiegti programą"</string>
- <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Perbraukite, kad galėtumėte tęsti"</string>
+ <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+ <skip />
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Bendrinti ekrano vaizdą išoriniame ekrane?"</string>
<string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Bus bendrinamas vidinio rodinio ekrano vaizdas. Priekinis rodinys bus išjungtas."</string>
<string name="mirror_display" msgid="2515262008898122928">"Bendrinti ekrano vaizdą"</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index bea683b..7139fdb 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -418,6 +418,10 @@
<string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Šajā vietā varat pievienot, noņemt un pārkārtot logrīkus"</string>
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Pievienot citus logrīkus"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Nospiediet un turiet, lai pielāgotu logrīkus."</string>
+ <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+ <skip />
+ <!-- no translation found for edit_widget (9030848101135393954) -->
+ <skip />
<string name="button_to_remove_widget" msgid="3948204829181214098">"Noņemt"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Pievienot logrīku"</string>
<string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Gatavs"</string>
@@ -1213,7 +1217,8 @@
<string name="assistant_attention_content_description" msgid="4166330881435263596">"Konstatēta lietotāja klātbūtne"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Iestatījumos iestatiet noklusējuma piezīmju lietotni."</string>
<string name="install_app" msgid="5066668100199613936">"Instalēt lietotni"</string>
- <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Velciet, lai turpinātu"</string>
+ <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+ <skip />
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Vai spoguļot ārējā displejā?"</string>
<string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Jūsu iekšējais displejs tiks spoguļots. Jūsu priekšējais displejs tiks izslēgts."</string>
<string name="mirror_display" msgid="2515262008898122928">"Spoguļot displeju"</string>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index 26192e5a..26e4caa 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -418,6 +418,10 @@
<string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Додајте, отстранете и прераспоредете ги виџетите во просторов"</string>
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Додајте повеќе виџети"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Притиснете долго за да ги приспособите виџетите"</string>
+ <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+ <skip />
+ <!-- no translation found for edit_widget (9030848101135393954) -->
+ <skip />
<string name="button_to_remove_widget" msgid="3948204829181214098">"Отстранува"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Додајте виџет"</string>
<string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Готово"</string>
@@ -1213,7 +1217,8 @@
<string name="assistant_attention_content_description" msgid="4166330881435263596">"Откриено е присуство на корисник"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Поставете стандардна апликација за белешки во „Поставки“"</string>
<string name="install_app" msgid="5066668100199613936">"Инсталирајте ја апликацијата"</string>
- <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Повлечете нагоре за да продолжите"</string>
+ <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+ <skip />
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Да се преслика на надворешниот екран?"</string>
<string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Вашиот внатрешен екран ќе се отслика. Вашиот преден екран ќе се исклучи."</string>
<string name="mirror_display" msgid="2515262008898122928">"Пресликај екран"</string>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index 8d3a8cc..181e2fd 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -418,6 +418,10 @@
<string name="cta_label_to_edit_widget" msgid="6496885074209203756">"ഈ സ്പെയ്സിൽ നിങ്ങളുടെ വിജറ്റുകൾ ചേർക്കുക, നീക്കം ചെയ്യുക, പുനഃക്രമീകരിക്കുക"</string>
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"കൂടുതൽ വിജറ്റുകൾ ചേർക്കുക"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"വിജറ്റുകൾ ഇഷ്ടാനുസൃതമാക്കാൻ ദീർഘനേരം അമർത്തുക"</string>
+ <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+ <skip />
+ <!-- no translation found for edit_widget (9030848101135393954) -->
+ <skip />
<string name="button_to_remove_widget" msgid="3948204829181214098">"നീക്കം ചെയ്യുക"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"വിജറ്റ് ചേർക്കുക"</string>
<string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"പൂർത്തിയായി"</string>
@@ -1213,7 +1217,8 @@
<string name="assistant_attention_content_description" msgid="4166330881435263596">"ഉപയോക്താവിന്റെ സാന്നിധ്യം കണ്ടെത്തി"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"ക്രമീകരണത്തിൽ കുറിപ്പുകൾക്കുള്ള ഡിഫോൾട്ട് ആപ്പ് സജ്ജീകരിക്കുക"</string>
<string name="install_app" msgid="5066668100199613936">"ആപ്പ് ഇൻസ്റ്റാൾ ചെയ്യൂ"</string>
- <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"തുടരാൻ സ്വൈപ്പ് ചെയ്യുക"</string>
+ <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+ <skip />
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"ബാഹ്യ ഡിസ്പ്ലേയിലേക്ക് മിറർ ചെയ്യണോ?"</string>
<string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"നിങ്ങളുടെ ഇന്നർ ഡിസ്പ്ലേ മിറർ ചെയ്യും. നിങ്ങളുടെ ഫ്രണ്ട് ഡിസ്പ്ലേ ഓഫാകും."</string>
<string name="mirror_display" msgid="2515262008898122928">"മിറർ ഡിസ്പ്ലേ"</string>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index 3380af4..8b8265d 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -418,6 +418,10 @@
<string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Энэ орон зайд виджетүүдээ нэмэх, хасах болон дахин эрэмбэлэх"</string>
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Илүү олон виджет нэмэх"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Виджетүүдийг өөрчлөхийн тулд удаан дарна уу"</string>
+ <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+ <skip />
+ <!-- no translation found for edit_widget (9030848101135393954) -->
+ <skip />
<string name="button_to_remove_widget" msgid="3948204829181214098">"Хасах"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Виджет нэмэх"</string>
<string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Болсон"</string>
@@ -1213,7 +1217,8 @@
<string name="assistant_attention_content_description" msgid="4166330881435263596">"Хэрэглэгч байгааг илрүүлсэн"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Тохиргоонд тэмдэглэлийн өгөгдмөл апп тохируулна уу"</string>
<string name="install_app" msgid="5066668100199613936">"Аппыг суулгах"</string>
- <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Үргэлжлүүлэхийн тулд шударна уу"</string>
+ <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+ <skip />
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Гадны дэлгэцэд тусгал үүсгэх үү?"</string>
<string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Таны дотоод дэлгэцийн тусгалыг үүсгэнэ. Таны урд талын дэлгэцийг унтраана."</string>
<string name="mirror_display" msgid="2515262008898122928">"Дэлгэцийн тусгал үүсгэх"</string>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index 58ceb79..b61d408 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -418,6 +418,10 @@
<string name="cta_label_to_edit_widget" msgid="6496885074209203756">"या स्पेसमध्ये तुमची विजेट जोडा, काढून टाका आणि पुन्हा क्रमाने लावा"</string>
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"आणखी विजेट जोडा"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"विजेट कस्टमाइझ करण्यासाठी प्रेस करून ठेवा"</string>
+ <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+ <skip />
+ <!-- no translation found for edit_widget (9030848101135393954) -->
+ <skip />
<string name="button_to_remove_widget" msgid="3948204829181214098">"काढून टाका"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"विजेट जोडा"</string>
<string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"पूर्ण झाले"</string>
@@ -1213,7 +1217,8 @@
<string name="assistant_attention_content_description" msgid="4166330881435263596">"वापरकर्त्याची उपस्थिती डिटेक्ट केली"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"सेटिंग्ज मध्ये डीफॉल्ट टिपा अॅप सेट करा"</string>
<string name="install_app" msgid="5066668100199613936">"अॅप इंस्टॉल करा"</string>
- <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"सुरू ठेवण्यासाठी स्वाइप करा"</string>
+ <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+ <skip />
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"बाह्य डिस्प्लेवर मिरर करायचे आहे का?"</string>
<string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"तुमचा अंतर्गत डिस्प्ले मिरर केला जाईल. तुमचा पुढील डिस्प्ले बंद केला जाईल."</string>
<string name="mirror_display" msgid="2515262008898122928">"डिस्प्ले मिरर करा"</string>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index 04e0170..86c0dd9 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -418,6 +418,10 @@
<string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Tambahkan, alih keluar dan susun semula widget anda dalam ruang ini"</string>
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Tambahkan lagi widget"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Tekan lama untuk menyesuaikan widget"</string>
+ <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+ <skip />
+ <!-- no translation found for edit_widget (9030848101135393954) -->
+ <skip />
<string name="button_to_remove_widget" msgid="3948204829181214098">"Alih keluar"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Tambahkan widget"</string>
<string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Selesai"</string>
@@ -1213,7 +1217,8 @@
<string name="assistant_attention_content_description" msgid="4166330881435263596">"Kehadiran pengguna dikesan"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Tetapkan apl nota lalai dalam Tetapan"</string>
<string name="install_app" msgid="5066668100199613936">"Pasang apl"</string>
- <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Leret untuk meneruskan proses"</string>
+ <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+ <skip />
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Paparkan pada paparan luaran?"</string>
<string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Paparan dalaman anda akan dicerminkan. Paparan depan anda akan dimatikan."</string>
<string name="mirror_display" msgid="2515262008898122928">"Segerakkan paparan"</string>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index 5b7fa6d..19c9c04 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -418,6 +418,10 @@
<string name="cta_label_to_edit_widget" msgid="6496885074209203756">"ဤနေရာတွင် သင့်ဝိဂျက်များကို ထည့်ရန်၊ ဖယ်ရှားရန်၊ ပြန်စီရန်"</string>
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"နောက်ထပ်ဝိဂျက်များ ထည့်ရန်"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"ဝိဂျက်များ စိတ်ကြိုက်လုပ်ရန် ကြာကြာနှိပ်ထားပါ"</string>
+ <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+ <skip />
+ <!-- no translation found for edit_widget (9030848101135393954) -->
+ <skip />
<string name="button_to_remove_widget" msgid="3948204829181214098">"ဖယ်ရှားရန်"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"ဝိဂျက်ထည့်ရန်"</string>
<string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"ပြီးပြီ"</string>
@@ -1213,7 +1217,8 @@
<string name="assistant_attention_content_description" msgid="4166330881435263596">"အသုံးပြုသူရှိကြောင်း တွေ့ရသည်"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"ဆက်တင်များတွင် မူရင်းမှတ်စုများအက်ပ် သတ်မှတ်ပါ"</string>
<string name="install_app" msgid="5066668100199613936">"အက်ပ် ထည့်သွင်းရန်"</string>
- <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"ရှေ့ဆက်ရန် ပွတ်ဆွဲပါ"</string>
+ <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+ <skip />
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"ပြင်ပဖန်သားပြင်သို့ စကရင်ပွားမလား။"</string>
<string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"အတွင်းပြကွက်ကို စကရင်ပွားပါမည်။ ရှေ့မျက်နှာပြင်ပြကွက်ကို ပိတ်မည်။"</string>
<string name="mirror_display" msgid="2515262008898122928">"ဖန်သားပြင်ကို စကရင်ပွားရန်"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 1dd377e..18fba66 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -418,6 +418,10 @@
<string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Legg til, fjern og omorganiser modulene i dette området"</string>
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Legg til flere moduler"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Trykk lenge for å tilpasse modulene"</string>
+ <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+ <skip />
+ <!-- no translation found for edit_widget (9030848101135393954) -->
+ <skip />
<string name="button_to_remove_widget" msgid="3948204829181214098">"Fjern"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Legg til modul"</string>
<string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Ferdig"</string>
@@ -1213,7 +1217,8 @@
<string name="assistant_attention_content_description" msgid="4166330881435263596">"Det er registrert at brukeren er til stede"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Du kan velge en standardapp for notater i Innstillinger"</string>
<string name="install_app" msgid="5066668100199613936">"Installer appen"</string>
- <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Sveip for å fortsette"</string>
+ <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+ <skip />
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Vil du speile til en ekstern skjerm?"</string>
<string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Den indre skjermen speiles. Den ytre skjermen slås av."</string>
<string name="mirror_display" msgid="2515262008898122928">"Speil skjermen"</string>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index 58baede..a192c93 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -418,6 +418,10 @@
<string name="cta_label_to_edit_widget" msgid="6496885074209203756">"यो स्पेसमा आफ्ना विजेटहरू हाल्नुहोस्, हटाउनुहोस् र तिनका क्रम फेरि मिलाउनुहोस्"</string>
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"थप विजेटहरू हाल्नुहोस्"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"विजेटहरू कस्टमाइज गर्न केही बेरसम्म थिच्नुहोस्"</string>
+ <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+ <skip />
+ <!-- no translation found for edit_widget (9030848101135393954) -->
+ <skip />
<string name="button_to_remove_widget" msgid="3948204829181214098">"हटाउनुहोस्"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"विजेट हाल्नुहोस्"</string>
<string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"पूरा भयो"</string>
@@ -1213,7 +1217,8 @@
<string name="assistant_attention_content_description" msgid="4166330881435263596">"प्रयोगकर्ता उपस्थित भएको कुरा पत्ता लागेको छ"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"सेटिङमा गई नोट बनाउने डिफल्ट एप तोक्नुहोस्"</string>
<string name="install_app" msgid="5066668100199613936">"एप इन्स्टल गर्नुहोस्"</string>
- <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"जारी राख्न स्वाइप गर्नुहोस्"</string>
+ <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+ <skip />
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"बाह्य डिस्प्लेमा मिरर गर्ने हो?"</string>
<string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"तपाईंको भित्री डिस्प्ले मिरर गरिने छ। तपाईंको अगाडिको डिस्प्ले अफ गरिने छ।"</string>
<string name="mirror_display" msgid="2515262008898122928">"डिस्प्ले मिरर गर्नुहोस्"</string>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index a882a28..d518a87 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -418,6 +418,10 @@
<string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Je widgets aan deze ruimte toevoegen, eruit verwijderen of opnieuw ordenen"</string>
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Meer widgets toevoegen"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Houd lang ingedrukt om widgets aan te passen"</string>
+ <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+ <skip />
+ <!-- no translation found for edit_widget (9030848101135393954) -->
+ <skip />
<string name="button_to_remove_widget" msgid="3948204829181214098">"Verwijderen"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Widget toevoegen"</string>
<string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Klaar"</string>
@@ -1213,7 +1217,8 @@
<string name="assistant_attention_content_description" msgid="4166330881435263596">"Gebruikersaanwezigheid is waargenomen"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Standaard notitie-app instellen in Instellingen"</string>
<string name="install_app" msgid="5066668100199613936">"App installeren"</string>
- <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Swipe om door te gaan"</string>
+ <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+ <skip />
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Spiegelen naar extern scherm?"</string>
<string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Het scherm aan de binnenkant wordt gemirrord. Het scherm aan de voorkant wordt uitgezet."</string>
<string name="mirror_display" msgid="2515262008898122928">"Scherm spiegelen"</string>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index 59145d4..38d0bd9 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -418,6 +418,10 @@
<string name="cta_label_to_edit_widget" msgid="6496885074209203756">"ଏହି ସ୍ପେସରେ ଆପଣଙ୍କ ୱିଜେଟଗୁଡ଼ିକୁ ଯୋଗ କରନ୍ତୁ, କାଢ଼ି ଦିଅନ୍ତୁ ଏବଂ ରିଅର୍ଡର କରନ୍ତୁ"</string>
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"ଅଧିକ ୱିଜେଟ ଯୋଗ କରନ୍ତୁ"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"ୱିଜେଟଗୁଡ଼ିକୁ କଷ୍ଟମାଇଜ କରିବା ପାଇଁ ଅଧିକ ସମୟ ଦବାନ୍ତୁ"</string>
+ <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+ <skip />
+ <!-- no translation found for edit_widget (9030848101135393954) -->
+ <skip />
<string name="button_to_remove_widget" msgid="3948204829181214098">"କାଢ଼ି ଦିଅନ୍ତୁ"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"ୱିଜେଟ ଯୋଗ କରନ୍ତୁ"</string>
<string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"ହୋଇଗଲା"</string>
@@ -1088,7 +1092,7 @@
<string name="empty_user_name" msgid="3389155775773578300">"ସାଙ୍ଗମାନେ"</string>
<string name="empty_status" msgid="5938893404951307749">"ଆଜି ରାତି ଚାଟ କରିବା!"</string>
<string name="status_before_loading" msgid="1500477307859631381">"ବିଷୟବସ୍ତୁ ଶୀଘ୍ର ଦେଖାଯିବ"</string>
- <string name="missed_call" msgid="4228016077700161689">"ମିସ୍ଡ କଲ୍"</string>
+ <string name="missed_call" msgid="4228016077700161689">"ମିସ୍ଡ କଲ"</string>
<string name="messages_count_overflow_indicator" msgid="7850934067082006043">"<xliff:g id="NUMBER">%d</xliff:g>+"</string>
<string name="people_tile_description" msgid="8154966188085545556">"ବର୍ତ୍ତମାନର ମେସେଜ, ମିସ୍ଡ କଲ ଏବଂ ସ୍ଥିତି ଅପଡେଟଗୁଡ଼ିକୁ ଦେଖନ୍ତୁ"</string>
<string name="people_tile_title" msgid="6589377493334871272">"ବାର୍ତ୍ତାଳାପ"</string>
@@ -1213,7 +1217,8 @@
<string name="assistant_attention_content_description" msgid="4166330881435263596">"ୟୁଜରଙ୍କ ଉପସ୍ଥିତି ଚିହ୍ନଟ କରାଯାଇଛି"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"ସେଟିଂସରେ ଡିଫଲ୍ଟ ନୋଟ୍ସ ଆପ ସେଟ କରନ୍ତୁ"</string>
<string name="install_app" msgid="5066668100199613936">"ଆପ ଇନଷ୍ଟଲ କରନ୍ତୁ"</string>
- <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"ଜାରି ରଖିବାକୁ ସ୍ୱାଇପ କରନ୍ତୁ"</string>
+ <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+ <skip />
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"ଏକ୍ସଟର୍ନଲ ଡିସପ୍ଲେକୁ ମିରର କରିବେ?"</string>
<string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"ଆପଣଙ୍କ ଇନର ଡିସପ୍ଲେକୁ ମିରର କରାଯିବ। ଆପଣଙ୍କ ଫ୍ରଣ୍ଟ ଡିସପ୍ଲେକୁ ବନ୍ଦ କରାଯିବ।"</string>
<string name="mirror_display" msgid="2515262008898122928">"ଡିସପ୍ଲେ ମିରର କରନ୍ତୁ"</string>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index be69c1e..fdbc0e5 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -418,6 +418,10 @@
<string name="cta_label_to_edit_widget" msgid="6496885074209203756">"ਇਸ ਜਗ੍ਹਾ ਵਿੱਚ ਆਪਣੇ ਵਿਜੇਟ ਸ਼ਾਮਲ ਕਰੋ, ਹਟਾਓ ਅਤੇ ਮੁੜ-ਕ੍ਰਮਬੱਧ ਕਰੋ"</string>
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"ਹੋਰ ਵਿਜੇਟ ਸ਼ਾਮਲ ਕਰੋ"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"ਵਿਜੇਟਾਂ ਨੂੰ ਵਿਉਂਤਬੱਧ ਕਰਨ ਲਈ ਦਬਾਈ ਰੱਖੋ"</string>
+ <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+ <skip />
+ <!-- no translation found for edit_widget (9030848101135393954) -->
+ <skip />
<string name="button_to_remove_widget" msgid="3948204829181214098">"ਹਟਾਓ"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"ਵਿਜੇਟ ਸ਼ਾਮਲ ਕਰੋ"</string>
<string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"ਹੋ ਗਿਆ"</string>
@@ -1213,7 +1217,8 @@
<string name="assistant_attention_content_description" msgid="4166330881435263596">"ਵਰਤੋਂਕਾਰ ਦੀ ਮੌਜੂਦਗੀ ਦਾ ਪਤਾ ਲਗਾਇਆ ਜਾਂਦਾ ਹੈ"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਜਾ ਕੇ ਪੂਰਵ-ਨਿਰਧਾਰਿਤ ਨੋਟ ਐਪ ਨੂੰ ਸੈੱਟ ਕਰੋ"</string>
<string name="install_app" msgid="5066668100199613936">"ਐਪ ਸਥਾਪਤ ਕਰੋ"</string>
- <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"ਜਾਰੀ ਰੱਖਣ ਲਈ ਸਵਾਈਪ ਕਰੋ"</string>
+ <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+ <skip />
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"ਕੀ ਬਾਹਰੀ ਡਿਸਪਲੇ \'ਤੇ ਪ੍ਰਤਿਬਿੰਬਿਤ ਕਰਨਾ ਹੈ?"</string>
<string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"ਤੁਹਾਡੀ ਅੰਦਰੂਨੀ ਡਿਸਪਲੇ ਪ੍ਰਤੀਬਿੰਬਤ ਕੀਤੀ ਜਾਵੇਗੀ। ਤੁਹਾਡੀ ਅਗਲੀ ਡਿਸਪਲੇ ਬੰਦ ਕਰ ਦਿੱਤੀ ਜਾਵੇਗੀ।"</string>
<string name="mirror_display" msgid="2515262008898122928">"ਡਿਸਪਲੇ ਨੂੰ ਪ੍ਰਤਿਬਿੰਬਿਤ ਕਰੋ"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 192614b..53a1a67c 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -418,6 +418,10 @@
<string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Dodawaj widżety, usuwaj je i zmieniaj ich kolejność w tym obszarze"</string>
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Dodaj więcej widżetów"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Przytrzymaj, aby dostosować widżety"</string>
+ <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+ <skip />
+ <!-- no translation found for edit_widget (9030848101135393954) -->
+ <skip />
<string name="button_to_remove_widget" msgid="3948204829181214098">"Usuń"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Dodaj widżet"</string>
<string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Gotowe"</string>
@@ -1213,7 +1217,8 @@
<string name="assistant_attention_content_description" msgid="4166330881435263596">"Wykryto obecność użytkownika"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Ustaw domyślną aplikację do obsługi notatek w Ustawieniach"</string>
<string name="install_app" msgid="5066668100199613936">"Zainstaluj aplikację"</string>
- <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Przesuń, aby kontynuować"</string>
+ <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+ <skip />
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Powielić na wyświetlaczu zewnętrznym?"</string>
<string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Powstanie odbicie lustrzane Twojego wewnętrznego ekranu. Przedni ekran zostanie wyłączony."</string>
<string name="mirror_display" msgid="2515262008898122928">"Powielaj obraz"</string>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 3ca10d3..3508558 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -418,6 +418,10 @@
<string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Adicione, remova e reorganize seus widgets neste espaço"</string>
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Adicione mais widgets"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Mantenha pressionado para personalizar widgets"</string>
+ <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+ <skip />
+ <!-- no translation found for edit_widget (9030848101135393954) -->
+ <skip />
<string name="button_to_remove_widget" msgid="3948204829181214098">"Remover"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Adicionar widget"</string>
<string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Concluído"</string>
@@ -1213,7 +1217,8 @@
<string name="assistant_attention_content_description" msgid="4166330881435263596">"Presença do usuário detectada"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Defina o app de notas padrão nas Configurações"</string>
<string name="install_app" msgid="5066668100199613936">"Instalar o app"</string>
- <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Deslize para continuar"</string>
+ <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+ <skip />
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Espelhar para a tela externa?"</string>
<string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Seu display interno será espelhado. O display frontal será desligado."</string>
<string name="mirror_display" msgid="2515262008898122928">"Espelhar tela"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 1656e27..3ac26f0 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -418,6 +418,10 @@
<string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Adicionar, remover e reordenar widgets neste espaço"</string>
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Adicionar mais widgets"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Mantenha premido para personalizar os widgets"</string>
+ <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+ <skip />
+ <!-- no translation found for edit_widget (9030848101135393954) -->
+ <skip />
<string name="button_to_remove_widget" msgid="3948204829181214098">"Remover"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Adicionar widget"</string>
<string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Concluir"</string>
@@ -1213,7 +1217,8 @@
<string name="assistant_attention_content_description" msgid="4166330881435263596">"Quando deteta a presença do utilizador"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Predefina a app de notas nas Definições"</string>
<string name="install_app" msgid="5066668100199613936">"Instalar app"</string>
- <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Deslize rapidamente para continuar"</string>
+ <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+ <skip />
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Espelhar para o ecrã externo?"</string>
<string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"O seu ecrã interior vai ser espelhado. O seu ecrã frontal vai ser desativado."</string>
<string name="mirror_display" msgid="2515262008898122928">"Espelhar ecrã"</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 3ca10d3..3508558 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -418,6 +418,10 @@
<string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Adicione, remova e reorganize seus widgets neste espaço"</string>
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Adicione mais widgets"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Mantenha pressionado para personalizar widgets"</string>
+ <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+ <skip />
+ <!-- no translation found for edit_widget (9030848101135393954) -->
+ <skip />
<string name="button_to_remove_widget" msgid="3948204829181214098">"Remover"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Adicionar widget"</string>
<string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Concluído"</string>
@@ -1213,7 +1217,8 @@
<string name="assistant_attention_content_description" msgid="4166330881435263596">"Presença do usuário detectada"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Defina o app de notas padrão nas Configurações"</string>
<string name="install_app" msgid="5066668100199613936">"Instalar o app"</string>
- <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Deslize para continuar"</string>
+ <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+ <skip />
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Espelhar para a tela externa?"</string>
<string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Seu display interno será espelhado. O display frontal será desligado."</string>
<string name="mirror_display" msgid="2515262008898122928">"Espelhar tela"</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index fa2aa1a..7cdc121 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -418,6 +418,10 @@
<string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Adaugă, elimină și reordonează widgeturile în acest spațiu"</string>
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Adaugă mai multe widgeturi"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Apasă lung pentru a personaliza widgeturi"</string>
+ <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+ <skip />
+ <!-- no translation found for edit_widget (9030848101135393954) -->
+ <skip />
<string name="button_to_remove_widget" msgid="3948204829181214098">"Elimină"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Adaugă un widget"</string>
<string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Gata"</string>
@@ -1213,7 +1217,8 @@
<string name="assistant_attention_content_description" msgid="4166330881435263596">"S-a detectat prezența utilizatorului"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Setează aplicația prestabilită de note din Setări"</string>
<string name="install_app" msgid="5066668100199613936">"Instalează aplicația"</string>
- <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Glisează pentru a continua"</string>
+ <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+ <skip />
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Oglindești pe ecranul extern?"</string>
<string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Ecranul interior va fi oglindit. Ecranul frontal va fi dezactivat."</string>
<string name="mirror_display" msgid="2515262008898122928">"Afișare în oglindă"</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 7cb509f..a059e55 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -418,6 +418,10 @@
<string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Добавление, удаление и упорядочивание виджетов в этом пространстве"</string>
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Добавить виджеты"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Нажмите и удерживайте, чтобы настроить виджеты."</string>
+ <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+ <skip />
+ <!-- no translation found for edit_widget (9030848101135393954) -->
+ <skip />
<string name="button_to_remove_widget" msgid="3948204829181214098">"Удалить"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Добавить виджет"</string>
<string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Готово"</string>
@@ -1213,7 +1217,8 @@
<string name="assistant_attention_content_description" msgid="4166330881435263596">"Обнаружен пользователь"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Задайте стандартное приложение для заметок в настройках."</string>
<string name="install_app" msgid="5066668100199613936">"Установить приложение"</string>
- <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Проведите по экрану, чтобы продолжить."</string>
+ <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+ <skip />
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Дублировать на внешний дисплей?"</string>
<string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Для внутреннего экрана включится дублирование. Передний экран будет отключен."</string>
<string name="mirror_display" msgid="2515262008898122928">"Дублировать"</string>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index 97d1c3d..ad7b241 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -418,6 +418,10 @@
<string name="cta_label_to_edit_widget" msgid="6496885074209203756">"මෙම අවකාශය තුළ ඔබේ විජට් එක් කරන්න, ඉවත් කරන්න, සහ නැවත අනුපිළිවෙල කරන්න"</string>
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"තවත් විජට් එක් කරන්න"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"විජට් අභිරුචිකරණය කිරීමට දිගු ඔබන්න"</string>
+ <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+ <skip />
+ <!-- no translation found for edit_widget (9030848101135393954) -->
+ <skip />
<string name="button_to_remove_widget" msgid="3948204829181214098">"ඉවත් කරන්න"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"විජට්ටුව එක් කරන්න"</string>
<string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"නිමයි"</string>
@@ -1213,7 +1217,8 @@
<string name="assistant_attention_content_description" msgid="4166330881435263596">"පරිශීලක රූපාකාරය අනාවරණය වේ"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"සැකසීම් තුළ පෙරනිමි සටහන් යෙදුම සකසන්න"</string>
<string name="install_app" msgid="5066668100199613936">"යෙදුම ස්ථාපනය කරන්න"</string>
- <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"ඉදිරියට යාමට ස්වයිප් කරන්න"</string>
+ <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+ <skip />
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"බාහිර සංදර්ශකයට දර්පණය කරන්න ද?"</string>
<string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"ඔබේ අභ්යන්තර සංදර්ශකය පිළිබිඹු වනු ඇත. ඔබේ ඉදිරිපස සංදර්ශකය ක්රියාවිරහිත වනු ඇත."</string>
<string name="mirror_display" msgid="2515262008898122928">"සංදර්ශකය දර්පණය කරන්න"</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index f1ff09e..e4162db 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -418,6 +418,10 @@
<string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Pridávajte aj odstraňujte miniaplikácie a meňte ich poradie v tomto priestore"</string>
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Pridať ďalšie miniaplikácie"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Miniaplikácie prispôsobíte dlhým stlačením"</string>
+ <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+ <skip />
+ <!-- no translation found for edit_widget (9030848101135393954) -->
+ <skip />
<string name="button_to_remove_widget" msgid="3948204829181214098">"Odstrániť"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Pridať miniaplikáciu"</string>
<string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Hotovo"</string>
@@ -1213,7 +1217,8 @@
<string name="assistant_attention_content_description" msgid="4166330881435263596">"Bola rozpoznaná prítomnosť používateľa"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Nastavte predvolenú aplikáciu na poznámky v Nastaveniach"</string>
<string name="install_app" msgid="5066668100199613936">"Inštalovať aplikáciu"</string>
- <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Pokračujte potiahnutím"</string>
+ <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+ <skip />
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Chcete zrkadliť na externú obrazovku?"</string>
<string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Vnútorná obrazovka bude zrkadlená. Predná obrazovka bude vypnutá."</string>
<string name="mirror_display" msgid="2515262008898122928">"Zrkadliť obrazovku"</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 8a9b624..c8f7dc1 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -418,6 +418,10 @@
<string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Dodajajte, odstranjujte in prerazporejajte pripomočke v tem prostoru"</string>
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Dodajte več pripomočkov"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Pridržite za prilagajanje pripomočkov"</string>
+ <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+ <skip />
+ <!-- no translation found for edit_widget (9030848101135393954) -->
+ <skip />
<string name="button_to_remove_widget" msgid="3948204829181214098">"Odstrani"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Dodajanje pripomočka"</string>
<string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Končano"</string>
@@ -1213,7 +1217,8 @@
<string name="assistant_attention_content_description" msgid="4166330881435263596">"Zaznana je prisotnost uporabnika"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Nastavite privzeto aplikacijo za zapiske v nastavitvah."</string>
<string name="install_app" msgid="5066668100199613936">"Namesti aplikacijo"</string>
- <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Povlecite za nadaljevanje"</string>
+ <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+ <skip />
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Želite zrcaliti na zunanji zaslon?"</string>
<string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Notranji zaslon bo zrcaljen. Sprednji zaslon bo izklopljen."</string>
<string name="mirror_display" msgid="2515262008898122928">"Zrcali zaslon"</string>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index de68a51..7dd89a1 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -418,6 +418,10 @@
<string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Shto, hiq dhe rirendit miniaplikacionet e tua në këtë hapësirë"</string>
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Shto miniaplikacione të tjera"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Shtyp gjatë për të personalizuar miniaplikacionet"</string>
+ <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+ <skip />
+ <!-- no translation found for edit_widget (9030848101135393954) -->
+ <skip />
<string name="button_to_remove_widget" msgid="3948204829181214098">"Hiq"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Shto miniaplikacionin"</string>
<string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"U krye"</string>
@@ -1213,7 +1217,8 @@
<string name="assistant_attention_content_description" msgid="4166330881435263596">"Është zbuluar prania e përdoruesit"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Cakto aplikacionin e parazgjedhur të shënimeve te \"Cilësimet\""</string>
<string name="install_app" msgid="5066668100199613936">"Instalo aplikacionin"</string>
- <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Rrëshqit shpejt për të vazhduar"</string>
+ <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+ <skip />
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Të pasqyrohet në ekranin e jashtëm?"</string>
<string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Ekrani i brendshëm do të pasqyrohet. Ekrani i parmë do të çaktivizohet."</string>
<string name="mirror_display" msgid="2515262008898122928">"Pasqyro ekranin"</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 28ff0ab..ca43617 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -418,6 +418,10 @@
<string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Додајте, уклоните и преуредите виџете у овом простору"</string>
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Додајте још виџета"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Дуги притисак за прилагођавање виџета"</string>
+ <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+ <skip />
+ <!-- no translation found for edit_widget (9030848101135393954) -->
+ <skip />
<string name="button_to_remove_widget" msgid="3948204829181214098">"Уклони"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Додај виџет"</string>
<string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Готово"</string>
@@ -1213,7 +1217,8 @@
<string name="assistant_attention_content_description" msgid="4166330881435263596">"Присуство корисника може да се открије"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Подесите подразумевану апликацију за белешке у Подешавањима"</string>
<string name="install_app" msgid="5066668100199613936">"Инсталирај апликацију"</string>
- <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Превуците да бисте наставили"</string>
+ <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+ <skip />
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Желите ли да пресликате на спољњи екран?"</string>
<string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Унутрашњи екран ће се пресликати. Предњи екран ће се искључити."</string>
<string name="mirror_display" msgid="2515262008898122928">"Пресликај екран"</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 8bc214f..078942d 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -418,6 +418,10 @@
<string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Lägg till, ta bort och ordna om dina widgetar i det här rummet"</string>
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Lägg till fler widgetar"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Tryck länge för att anpassa widgetar"</string>
+ <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+ <skip />
+ <!-- no translation found for edit_widget (9030848101135393954) -->
+ <skip />
<string name="button_to_remove_widget" msgid="3948204829181214098">"Ta bort"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Lägg till widget"</string>
<string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Klar"</string>
@@ -1213,7 +1217,8 @@
<string name="assistant_attention_content_description" msgid="4166330881435263596">"Användarnärvaro har upptäckts"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Ställ in en standardapp för anteckningar i inställningarna"</string>
<string name="install_app" msgid="5066668100199613936">"Installera appen"</string>
- <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Svep för att fortsätta"</string>
+ <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+ <skip />
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Vill du spegla till extern skärm?"</string>
<string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Den inre skärmen speglas. Den främre skärmen stängs av."</string>
<string name="mirror_display" msgid="2515262008898122928">"Spegla skärm"</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 2aec42e..b056cf7 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -418,6 +418,10 @@
<string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Ongeza, ondoa na upange upya wijeti zako katika nafasi hii"</string>
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Weka wijeti zingine"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Bonyeza kwa muda mrefu uweke mapendeleo ya wijeti"</string>
+ <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+ <skip />
+ <!-- no translation found for edit_widget (9030848101135393954) -->
+ <skip />
<string name="button_to_remove_widget" msgid="3948204829181214098">"Ondoa"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Ongeza wijeti"</string>
<string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Nimemaliza"</string>
@@ -1213,7 +1217,8 @@
<string name="assistant_attention_content_description" msgid="4166330881435263596">"Imetambua uwepo wa mtumiaji"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Teua programu chaguomsingi ya madokezo katika Mipangilio"</string>
<string name="install_app" msgid="5066668100199613936">"Sakinisha programu"</string>
- <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Telezesha kidole ili uendelee"</string>
+ <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+ <skip />
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Ungependa kuonyesha kwenye skrini ya nje?"</string>
<string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Mwonekano wa ndani wa kifaa chako utaakisiwa. Mwonekano wa mbele wa kifaa chako utazimwa."</string>
<string name="mirror_display" msgid="2515262008898122928">"Akisi skrini"</string>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index 5319053..42db082 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -418,6 +418,10 @@
<string name="cta_label_to_edit_widget" msgid="6496885074209203756">"இந்த இடத்தில் உங்கள் விட்ஜெட்களைச் சேர்க்கலாம், அகற்றலாம், மறுவரிசைப்படுத்தலாம்"</string>
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"கூடுதல் விட்ஜெட்களைச் சேருங்கள்"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"விட்ஜெட்களைப் பிரத்தியேகமாக்க நீண்ட நேரம் அழுத்துக"</string>
+ <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+ <skip />
+ <!-- no translation found for edit_widget (9030848101135393954) -->
+ <skip />
<string name="button_to_remove_widget" msgid="3948204829181214098">"அகற்றும்"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"விட்ஜெட்டைச் சேர்"</string>
<string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"முடிந்தது"</string>
@@ -1213,7 +1217,8 @@
<string name="assistant_attention_content_description" msgid="4166330881435263596">"பயனர் கண்டறியப்பட்டுள்ளார்"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"குறிப்பு எடுப்பதற்கான இயல்புநிலை ஆப்ஸை அமைப்புகளில் அமையுங்கள்"</string>
<string name="install_app" msgid="5066668100199613936">"ஆப்ஸை நிறுவுங்கள்"</string>
- <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"ஸ்வைப் செய்து தொடரலாம்"</string>
+ <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+ <skip />
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"வெளிப்புறக் காட்சிக்கு மிரர் செய்யவா?"</string>
<string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"உங்கள் உட்புற டிஸ்பிளே பிரதிபலிக்கப்படும். உங்கள் முன்புற டிஸ்பிளே முடக்கப்படும்."</string>
<string name="mirror_display" msgid="2515262008898122928">"டிஸ்பிளேயை மிரர் செய்"</string>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index efb8b98..de866a0 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -418,6 +418,10 @@
<string name="cta_label_to_edit_widget" msgid="6496885074209203756">"ఈ స్పేస్లో మీ విడ్జెట్లను జోడించండి, తీసివేయండి, క్రమపద్ధతిలో అమర్చండి"</string>
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"మరిన్ని విడ్జెట్లను జోడించండి"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"విడ్జెట్లను అనుకూలీకరించడానికి, నొక్కి, ఉంచండి"</string>
+ <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+ <skip />
+ <!-- no translation found for edit_widget (9030848101135393954) -->
+ <skip />
<string name="button_to_remove_widget" msgid="3948204829181214098">"తీసివేయండి"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"విడ్జెట్ను జోడించండి"</string>
<string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"పూర్తయింది"</string>
@@ -1213,7 +1217,8 @@
<string name="assistant_attention_content_description" msgid="4166330881435263596">"యూజర్ ఉనికి గుర్తించబడింది"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"సెట్టింగ్లలో ఆటోమేటిక్గా ఉండేలా ఒక నోట్స్ యాప్ను సెట్ చేసుకోండి"</string>
<string name="install_app" msgid="5066668100199613936">"యాప్ను ఇన్స్టాల్ చేయండి"</string>
- <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"కొనసాగించడానికి స్వైప్ చేయండి"</string>
+ <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+ <skip />
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"ఎక్స్టర్నల్ డిస్ప్లేకి మిర్రర్ చేయాలా?"</string>
<string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"మీ లోపలి డిస్ప్లే మిర్రర్ చేయబడుతుంది. మీ ముందు వైపు డిస్ప్లే ఆఫ్ చేయబడుతుంది."</string>
<string name="mirror_display" msgid="2515262008898122928">"మిర్రర్ డిస్ప్లే"</string>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 78a45d6..341a462 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -418,6 +418,10 @@
<string name="cta_label_to_edit_widget" msgid="6496885074209203756">"เพิ่ม นำออก และจัดลำดับวิดเจ็ตในพื้นที่นี้ใหม่"</string>
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"เพิ่มวิดเจ็ตอีก"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"กดค้างเพื่อปรับแต่งวิดเจ็ต"</string>
+ <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+ <skip />
+ <!-- no translation found for edit_widget (9030848101135393954) -->
+ <skip />
<string name="button_to_remove_widget" msgid="3948204829181214098">"นำออก"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"เพิ่มวิดเจ็ต"</string>
<string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"เสร็จสิ้น"</string>
@@ -1213,7 +1217,8 @@
<string name="assistant_attention_content_description" msgid="4166330881435263596">"ตรวจพบการแสดงข้อมูลของผู้ใช้"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"กำหนดแอปการจดบันทึกเริ่มต้นในการตั้งค่า"</string>
<string name="install_app" msgid="5066668100199613936">"ติดตั้งแอป"</string>
- <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"ปัดเพื่อทำต่อ"</string>
+ <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+ <skip />
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"มิเรอร์ไปยังจอแสดงผลภายนอกไหม"</string>
<string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"ระบบจะมิเรอร์หน้าจอด้านใน และจะปิดหน้าจอด้านหน้า"</string>
<string name="mirror_display" msgid="2515262008898122928">"มิเรอร์จอแสดงผล"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 9ede0c7..3ac3d3a 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -418,6 +418,10 @@
<string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Magdagdag, mag-alis, at baguhin ang ayos ng iyong mga widget sa space na ito"</string>
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Magdagdag ng higit pang widget"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Pindutin nang matagal para i-customize ang mga widget"</string>
+ <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+ <skip />
+ <!-- no translation found for edit_widget (9030848101135393954) -->
+ <skip />
<string name="button_to_remove_widget" msgid="3948204829181214098">"Alisin"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Magdagdag ng widget"</string>
<string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Tapos na"</string>
@@ -1213,7 +1217,8 @@
<string name="assistant_attention_content_description" msgid="4166330881435263596">"Na-detect ang presensya ng user"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Magtakda ng default na app sa pagtatala sa Mga Setting"</string>
<string name="install_app" msgid="5066668100199613936">"I-install ang app"</string>
- <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Mag-swipe para magpatuloy"</string>
+ <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+ <skip />
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"I-mirror sa external na display?"</string>
<string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Imi-mirror ang inner display mo. Io-off ang iyong front display."</string>
<string name="mirror_display" msgid="2515262008898122928">"I-mirror ang display"</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index ef5d06e..9a09961 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -418,6 +418,10 @@
<string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Bu alanda widget\'larınızı ekleyin, kaldırın ve yeniden sıralayın"</string>
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Daha fazla widget ekle"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Widget\'ları özelleştirmek için uzun basın"</string>
+ <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+ <skip />
+ <!-- no translation found for edit_widget (9030848101135393954) -->
+ <skip />
<string name="button_to_remove_widget" msgid="3948204829181214098">"Kaldır"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Widget ekle"</string>
<string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Bitti"</string>
@@ -1213,7 +1217,8 @@
<string name="assistant_attention_content_description" msgid="4166330881435263596">"Kullanıcı varlığı algılandı"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Ayarlar\'ı kullanarak varsayılan notlar ayarlayın"</string>
<string name="install_app" msgid="5066668100199613936">"Uygulamayı yükle"</string>
- <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Devam etmek için kaydırın"</string>
+ <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+ <skip />
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Harici ekrana yansıtılsın mı?"</string>
<string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"İç ekranınız yansıtılacak. Ön ekranınız kapatılacak."</string>
<string name="mirror_display" msgid="2515262008898122928">"Ekranı yansıt"</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 700a8a0..152d93c 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -418,6 +418,10 @@
<string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Додати, вилучити чи впорядкувати віджети в цьому просторі"</string>
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Додати більше віджетів"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Утримуйте, щоб налаштувати віджети"</string>
+ <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+ <skip />
+ <!-- no translation found for edit_widget (9030848101135393954) -->
+ <skip />
<string name="button_to_remove_widget" msgid="3948204829181214098">"Видалити"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Додати віджет"</string>
<string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Готово"</string>
@@ -1213,7 +1217,8 @@
<string name="assistant_attention_content_description" msgid="4166330881435263596">"Виявлено присутність користувача"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Призначте стандартний додаток для нотаток у налаштуваннях"</string>
<string name="install_app" msgid="5066668100199613936">"Установити додаток"</string>
- <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Щоб продовжити, проведіть пальцем по екрану"</string>
+ <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+ <skip />
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Дублювати на зовнішньому екрані?"</string>
<string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Ваш внутрішній екран буде продубльовано. Передній екран буде вимкнено."</string>
<string name="mirror_display" msgid="2515262008898122928">"Дублювати екран"</string>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index a1fab6c5..2ec5007 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -418,6 +418,10 @@
<string name="cta_label_to_edit_widget" msgid="6496885074209203756">"اس اسپیس میں اپنے ویجٹس شامل کریں، ہٹائیں اور دوبارہ ترتیب دیں"</string>
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"مزید ویجٹس شامل کریں"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"ویجٹس کو حسب ضرورت بنانے کے لیے لانگ پریس کریں"</string>
+ <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+ <skip />
+ <!-- no translation found for edit_widget (9030848101135393954) -->
+ <skip />
<string name="button_to_remove_widget" msgid="3948204829181214098">"ہٹائیں"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"ویجیٹ شامل کریں"</string>
<string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"ہو گیا"</string>
@@ -1213,7 +1217,8 @@
<string name="assistant_attention_content_description" msgid="4166330881435263596">"صارف کی موجودگی کا پتہ چلا ہے"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"ترتیبات میں ڈیفالٹ نوٹس ایپ سیٹ کریں"</string>
<string name="install_app" msgid="5066668100199613936">"ایپ انسٹال کریں"</string>
- <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"جاری رکھنے کے لیے سوائپ کریں"</string>
+ <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+ <skip />
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"بیرونی ڈسپلے پر مرر کریں؟"</string>
<string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"آپ کے اندرونی ڈسپلے کو دو طرفہ مطابقت پذیر بنایا جائے گا۔ آپ کا فرنٹ ڈسپلے آف ہو جائے گا۔"</string>
<string name="mirror_display" msgid="2515262008898122928">"ڈسپلے کو مرر کریں"</string>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index 6478f52..8bcda40 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -418,6 +418,10 @@
<string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Bu xonadagi vidjetlaringizni olib tashlang, tartibini oʻzgartiring va yangisini qoʻshing"</string>
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Koʻproq vidjetlar qoʻshish"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Vidjetlarni sozlash uchun bosib turing"</string>
+ <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+ <skip />
+ <!-- no translation found for edit_widget (9030848101135393954) -->
+ <skip />
<string name="button_to_remove_widget" msgid="3948204829181214098">"Olib tashlash"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Vidjet kiritish"</string>
<string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Tayyor"</string>
@@ -1213,7 +1217,8 @@
<string name="assistant_attention_content_description" msgid="4166330881435263596">"Foydalanuvchi aniqlandi"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Standart qaydlar ilovasini Sozlamalar orqali tanlang"</string>
<string name="install_app" msgid="5066668100199613936">"Ilovani oʻrnatish"</string>
- <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Davom etish uchun suring"</string>
+ <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+ <skip />
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Tashqi displeyda aks ettirilsinmi?"</string>
<string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Ichki ekran uchun aks ettirish yoqiladi. Old ekran oʻchiriladi."</string>
<string name="mirror_display" msgid="2515262008898122928">"Displeyni aks ettirish"</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index e425992..51d9c48 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -418,6 +418,10 @@
<string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Thêm, xoá và sắp xếp lại các tiện ích trong không gian này."</string>
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Thêm tiện ích khác"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Nhấn và giữ để tuỳ chỉnh tiện ích"</string>
+ <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+ <skip />
+ <!-- no translation found for edit_widget (9030848101135393954) -->
+ <skip />
<string name="button_to_remove_widget" msgid="3948204829181214098">"Xoá"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Thêm tiện ích"</string>
<string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Xong"</string>
@@ -1213,7 +1217,8 @@
<string name="assistant_attention_content_description" msgid="4166330881435263596">"Phát hiện thấy người dùng đang hiện diện"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Đặt ứng dụng ghi chú mặc định trong phần Cài đặt"</string>
<string name="install_app" msgid="5066668100199613936">"Cài đặt ứng dụng"</string>
- <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Vuốt để tiếp tục"</string>
+ <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+ <skip />
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Phản chiếu sang màn hình ngoài?"</string>
<string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Màn hình trong của bạn sẽ được phản chiếu. Màn hình ngoài của bạn sẽ tắt."</string>
<string name="mirror_display" msgid="2515262008898122928">"Phản chiếu màn hình"</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 1c6fb41..847418a 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -418,6 +418,10 @@
<string name="cta_label_to_edit_widget" msgid="6496885074209203756">"在此空间内添加、移除和重新排列您的微件"</string>
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"添加更多微件"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"长按即可自定义微件"</string>
+ <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+ <skip />
+ <!-- no translation found for edit_widget (9030848101135393954) -->
+ <skip />
<string name="button_to_remove_widget" msgid="3948204829181214098">"移除"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"添加微件"</string>
<string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"完成"</string>
@@ -1213,7 +1217,8 @@
<string name="assistant_attention_content_description" msgid="4166330881435263596">"检测到用户存在"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"在设置中设置默认记事应用"</string>
<string name="install_app" msgid="5066668100199613936">"安装应用"</string>
- <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"滑动可继续操作"</string>
+ <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+ <skip />
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"镜像到外接显示屏?"</string>
<string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"系统将镜像您的内屏,而关闭外屏。"</string>
<string name="mirror_display" msgid="2515262008898122928">"镜像到显示屏"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index c6a1bd8..b5a6089 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -418,6 +418,10 @@
<string name="cta_label_to_edit_widget" msgid="6496885074209203756">"增、移除小工具,以及調整小工具在此空間中的位置"</string>
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"新增更多小工具"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"長按即可自訂小工具"</string>
+ <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+ <skip />
+ <!-- no translation found for edit_widget (9030848101135393954) -->
+ <skip />
<string name="button_to_remove_widget" msgid="3948204829181214098">"移除"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"新增小工具"</string>
<string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"完成"</string>
@@ -1213,7 +1217,8 @@
<string name="assistant_attention_content_description" msgid="4166330881435263596">"偵測到使用者動態"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"在「設定」中指定預設筆記應用程式"</string>
<string name="install_app" msgid="5066668100199613936">"安裝應用程式"</string>
- <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"輕掃即可繼續瀏覽"</string>
+ <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+ <skip />
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"要鏡像投射至外部顯示屏嗎?"</string>
<string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"鏡像畫面將顯示在內部螢幕,前方螢幕則會關閉。"</string>
<string name="mirror_display" msgid="2515262008898122928">"鏡像顯示"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 5231a06..417b70e 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -418,6 +418,10 @@
<string name="cta_label_to_edit_widget" msgid="6496885074209203756">"新增、移除小工具,以及調整小工具在這個空間中的位置"</string>
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"新增更多小工具"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"長按即可自訂小工具"</string>
+ <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+ <skip />
+ <!-- no translation found for edit_widget (9030848101135393954) -->
+ <skip />
<string name="button_to_remove_widget" msgid="3948204829181214098">"移除"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"新增小工具"</string>
<string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"完成"</string>
@@ -1213,7 +1217,8 @@
<string name="assistant_attention_content_description" msgid="4166330881435263596">"偵測到使用者"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"在「設定」中指定預設記事應用程式"</string>
<string name="install_app" msgid="5066668100199613936">"安裝應用程式"</string>
- <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"滑動畫面繼續瀏覽"</string>
+ <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+ <skip />
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"要以鏡像方式投放至外部螢幕嗎?"</string>
<string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"鏡像畫面將顯示在內螢幕,封面螢幕則會關閉。"</string>
<string name="mirror_display" msgid="2515262008898122928">"鏡像顯示"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 10ee16d..795ed38 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -418,6 +418,10 @@
<string name="cta_label_to_edit_widget" msgid="6496885074209203756">"Engeza, susa, futhi uhlele kabusha amawijethi akho kulesi sikhala"</string>
<string name="cta_label_to_open_widget_picker" msgid="3874946756976360699">"Engeza amawijethi engeziwe"</string>
<string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Cindezela isikhathi eside ukuze wenze ngokwezifiso amawijethi"</string>
+ <!-- no translation found for button_to_configure_widgets_text (4191862850185256901) -->
+ <skip />
+ <!-- no translation found for edit_widget (9030848101135393954) -->
+ <skip />
<string name="button_to_remove_widget" msgid="3948204829181214098">"Susa"</string>
<string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Engeza iwijethi"</string>
<string name="hub_mode_editing_exit_button_text" msgid="3704686734192264771">"Kwenziwe"</string>
@@ -1213,7 +1217,8 @@
<string name="assistant_attention_content_description" msgid="4166330881435263596">"Ubukhona bomsebenzisi butholakele"</string>
<string name="set_default_notes_app_toast_content" msgid="2812374329662610753">"Setha i-app yamanothi azenzakalelayo Kumsethingi"</string>
<string name="install_app" msgid="5066668100199613936">"Faka i-app"</string>
- <string name="dismissible_keyguard_swipe" msgid="2213369651289613196">"Swayipha ukuze uqhubeke"</string>
+ <!-- no translation found for dismissible_keyguard_swipe (8377597870094949432) -->
+ <skip />
<string name="connected_display_dialog_start_mirroring" msgid="6237895789920854982">"Fanisa nesibonisi sangaphandle?"</string>
<string name="connected_display_dialog_dual_display_stop_warning" msgid="4174707498892447947">"Isibonisi sakho sangaphakathi sizoboniswa. Isibonisi sakho sangaphambili sizovalwa."</string>
<string name="mirror_display" msgid="2515262008898122928">"Isibonisi sokufanisa"</string>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 3839dd9..307a619 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -29,6 +29,9 @@
<color name="status_bar_icons_hover_color_light">#38FFFFFF</color> <!-- 22% white -->
<color name="status_bar_icons_hover_color_dark">#38000000</color> <!-- 22% black -->
+ <!-- The dark background color behind the shade -->
+ <color name="shade_scrim_background_dark">@*android:color/black</color>
+
<!-- The color of the background in the separated list of the Global Actions menu -->
<color name="global_actions_separated_background">#F5F5F5</color>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 47ac96c..7943588 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1077,8 +1077,6 @@
<!-- Indicator on keyguard to start the communal tutorial. [CHAR LIMIT=100] -->
<string name="communal_tutorial_indicator_text">Swipe left to start the communal tutorial</string>
- <!-- Description for the button that opens the widget editor on click. [CHAR LIMIT=50] -->
- <string name="button_to_open_widget_editor">Open the widget editor</string>
<!-- Text for CTA button that launches the hub mode widget editor on click. [CHAR LIMIT=50] -->
<string name="cta_tile_button_to_open_widget_editor">Customize</string>
<!-- Text for CTA button that dismisses the tile on click. [CHAR LIMIT=50] -->
@@ -1750,6 +1748,9 @@
<!-- Notification: Snooze panel: Snooze undo button label. [CHAR LIMIT=50]-->
<string name="snooze_undo">Undo</string>
+ <!-- Notification: Snooze panel: Snooze undo content description for a11y. [CHAR LIMIT=NONE]-->
+ <string name="snooze_undo_content_description">Undo notification snooze</string>
+
<!-- Notification: Snooze panel: message indicating how long the notification was snoozed for. [CHAR LIMIT=100]-->
<string name="snoozed_for_time">Snoozed for <xliff:g id="time_amount" example="15 minutes">%1$s</xliff:g></string>
diff --git a/packages/SystemUI/shared/biometrics/src/com/android/systemui/biometrics/shared/model/FingerprintSensorType.kt b/packages/SystemUI/shared/biometrics/src/com/android/systemui/biometrics/shared/model/FingerprintSensorType.kt
index a00cdfa..7c674c8 100644
--- a/packages/SystemUI/shared/biometrics/src/com/android/systemui/biometrics/shared/model/FingerprintSensorType.kt
+++ b/packages/SystemUI/shared/biometrics/src/com/android/systemui/biometrics/shared/model/FingerprintSensorType.kt
@@ -47,3 +47,14 @@
FingerprintSensorProperties.TYPE_HOME_BUTTON -> FingerprintSensorType.HOME_BUTTON
else -> throw IllegalArgumentException("Invalid SensorType value: $this")
}
+
+/** Convert [this] to corresponding [Int] */
+fun FingerprintSensorType.toInt(): Int =
+ when (this) {
+ FingerprintSensorType.UNKNOWN -> FingerprintSensorProperties.TYPE_UNKNOWN
+ FingerprintSensorType.REAR -> FingerprintSensorProperties.TYPE_REAR
+ FingerprintSensorType.UDFPS_ULTRASONIC -> FingerprintSensorProperties.TYPE_UDFPS_ULTRASONIC
+ FingerprintSensorType.UDFPS_OPTICAL -> FingerprintSensorProperties.TYPE_UDFPS_OPTICAL
+ FingerprintSensorType.POWER_BUTTON -> FingerprintSensorProperties.TYPE_POWER_BUTTON
+ FingerprintSensorType.HOME_BUTTON -> FingerprintSensorProperties.TYPE_HOME_BUTTON
+ }
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java
index f094102..d4ac195 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java
@@ -40,7 +40,15 @@
*/
public static RemoteAnimationTarget[] wrapApps(TransitionInfo info,
SurfaceControl.Transaction t, ArrayMap<SurfaceControl, SurfaceControl> leashMap) {
- return wrap(info, t, leashMap, new TransitionUtil.LeafTaskFilter());
+ // LeafTaskFilter is order-dependent, so the same object needs to be used for all Change
+ // objects. That's why it's constructed here and captured by the lambda instead of building
+ // a new one ad hoc every time.
+ TransitionUtil.LeafTaskFilter taskFilter = new TransitionUtil.LeafTaskFilter();
+ return wrap(info, t, leashMap, (change) -> {
+ // Intra-task activity -> activity transitions should be categorized as apps.
+ if (change.getActivityComponent() != null) return true;
+ return taskFilter.test(change);
+ });
}
/**
@@ -53,8 +61,12 @@
*/
public static RemoteAnimationTarget[] wrapNonApps(TransitionInfo info, boolean wallpapers,
SurfaceControl.Transaction t, ArrayMap<SurfaceControl, SurfaceControl> leashMap) {
- return wrap(info, t, leashMap, (change) -> (wallpapers
- ? TransitionUtil.isWallpaper(change) : TransitionUtil.isNonApp(change)));
+ return wrap(info, t, leashMap, (change) -> {
+ // Intra-task activity -> activity transitions should be categorized as apps.
+ if (change.getActivityComponent() != null) return false;
+ return wallpapers
+ ? TransitionUtil.isWallpaper(change) : TransitionUtil.isNonApp(change);
+ });
}
private static RemoteAnimationTarget[] wrap(TransitionInfo info,
diff --git a/packages/SystemUI/src/com/android/keyguard/NumPadButton.java b/packages/SystemUI/src/com/android/keyguard/NumPadButton.java
index 76f93e1..a81c1b0 100644
--- a/packages/SystemUI/src/com/android/keyguard/NumPadButton.java
+++ b/packages/SystemUI/src/com/android/keyguard/NumPadButton.java
@@ -26,6 +26,7 @@
import android.graphics.drawable.VectorDrawable;
import android.util.AttributeSet;
import android.view.MotionEvent;
+import android.view.accessibility.AccessibilityNodeInfo;
import androidx.annotation.Nullable;
@@ -145,4 +146,10 @@
mAnimator = null;
}
}
+
+ @Override
+ public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
+ super.onInitializeAccessibilityNodeInfo(info);
+ info.setTextEntryKey(true);
+ }
}
diff --git a/packages/SystemUI/src/com/android/keyguard/NumPadKey.java b/packages/SystemUI/src/com/android/keyguard/NumPadKey.java
index 871d57d..dcfa775 100644
--- a/packages/SystemUI/src/com/android/keyguard/NumPadKey.java
+++ b/packages/SystemUI/src/com/android/keyguard/NumPadKey.java
@@ -30,7 +30,7 @@
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
-import android.view.accessibility.AccessibilityManager;
+import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.TextView;
import androidx.annotation.Nullable;
@@ -105,8 +105,6 @@
}
setOnClickListener(mListener);
- setOnHoverListener(new LiftToActivateListener(
- (AccessibilityManager) context.getSystemService(Context.ACCESSIBILITY_SERVICE)));
mPM = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(
@@ -240,4 +238,10 @@
public void setAnimationEnabled(boolean enabled) {
mAnimationsEnabled = enabled;
}
+
+ @Override
+ public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
+ super.onInitializeAccessibilityNodeInfo(info);
+ info.setTextEntryKey(true);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuInfoRepository.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuInfoRepository.java
index 0538e7d..4a06ae9 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuInfoRepository.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuInfoRepository.java
@@ -21,7 +21,6 @@
import static android.provider.Settings.Secure.ACCESSIBILITY_FLOATING_MENU_OPACITY;
import static android.provider.Settings.Secure.ACCESSIBILITY_FLOATING_MENU_SIZE;
import static android.provider.Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES;
-import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_BUTTON;
import static com.android.internal.accessibility.dialog.AccessibilityTargetHelper.getTargets;
import static com.android.systemui.accessibility.floatingmenu.MenuFadeEffectInfoKt.DEFAULT_FADE_EFFECT_IS_ENABLED;
@@ -47,6 +46,7 @@
import androidx.annotation.NonNull;
+import com.android.internal.accessibility.common.ShortcutConstants;
import com.android.internal.accessibility.dialog.AccessibilityTarget;
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.Prefs;
@@ -182,7 +182,7 @@
}
void loadMenuTargetFeatures(OnInfoReady<List<AccessibilityTarget>> callback) {
- callback.onReady(getTargets(mContext, ACCESSIBILITY_BUTTON));
+ callback.onReady(getTargets(mContext, ShortcutConstants.UserShortcutType.SOFTWARE));
}
void loadMenuSizeType(OnInfoReady<Integer> callback) {
@@ -223,7 +223,7 @@
private void onTargetFeaturesChanged() {
mSettingsContentsCallback.onTargetFeaturesChanged(
- getTargets(mContext, ACCESSIBILITY_BUTTON));
+ getTargets(mContext, ShortcutConstants.UserShortcutType.SOFTWARE));
}
private Position getStartPosition() {
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuView.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuView.java
index 334cc87..035ccbd 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuView.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuView.java
@@ -226,15 +226,15 @@
// onArrivalAtPosition() is called at the end of the animation.
} else {
mMenuAnimationController.moveToPosition(position);
- onArrivalAtPosition(); // no animation, so we call this immediately.
+ onArrivalAtPosition(true); // no animation, so we call this immediately.
}
}
- void onArrivalAtPosition() {
+ void onArrivalAtPosition(boolean moveToEdgeIfTucked) {
final PointF position = getMenuPosition();
onBoundsInParentChanged((int) position.x, (int) position.y);
- if (isMoveToTucked()) {
+ if (isMoveToTucked() && moveToEdgeIfTucked) {
mMenuAnimationController.moveToEdgeAndHide();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayer.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayer.java
index bb5364d..f2e9531 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayer.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayer.java
@@ -17,7 +17,6 @@
package com.android.systemui.accessibility.floatingmenu;
import static android.view.WindowInsets.Type.ime;
-import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_SHORTCUT_KEY;
import static androidx.core.view.WindowInsetsCompat.Type;
@@ -64,6 +63,7 @@
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.RecyclerViewAccessibilityDelegate;
+import com.android.internal.accessibility.common.ShortcutConstants;
import com.android.internal.accessibility.dialog.AccessibilityTarget;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.messages.nano.SystemMessageProto;
@@ -154,7 +154,7 @@
final List<ComponentName> hardwareKeyShortcutComponents =
mAccessibilityManager.getAccessibilityShortcutTargets(
- ACCESSIBILITY_SHORTCUT_KEY)
+ ShortcutConstants.UserShortcutType.HARDWARE)
.stream()
.map(ComponentName::unflattenFromString)
.toList();
@@ -446,7 +446,7 @@
}
}
if (Flags.floatingMenuImeDisplacementAnimation()) {
- mMenuView.onArrivalAtPosition();
+ mMenuView.onArrivalAtPosition(false);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractor.kt b/packages/SystemUI/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractor.kt
index fdccad1..8ca083f 100644
--- a/packages/SystemUI/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractor.kt
@@ -30,11 +30,16 @@
import com.android.systemui.authentication.shared.model.AuthenticationWipeModel.WipeTarget
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.user.domain.interactor.SelectedUserInteractor
import com.android.systemui.util.time.SystemClock
import javax.inject.Inject
import kotlin.math.max
+import kotlin.time.Duration
+import kotlin.time.Duration.Companion.seconds
+import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.SharedFlow
@@ -44,6 +49,7 @@
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
+import kotlinx.coroutines.launch
/**
* Hosts application business logic related to user authentication.
@@ -57,6 +63,7 @@
@Inject
constructor(
@Application private val applicationScope: CoroutineScope,
+ @Background private val backgroundDispatcher: CoroutineDispatcher,
private val repository: AuthenticationRepository,
private val selectedUserInteractor: SelectedUserInteractor,
) {
@@ -227,6 +234,11 @@
if (authenticationResult.isSuccessful) {
repository.reportAuthenticationAttempt(isSuccessful = true)
_onAuthenticationResult.emit(true)
+
+ // Force a garbage collection in an attempt to erase any credentials left in memory.
+ // Do it after a 5-sec delay to avoid making the bouncer dismiss animation janky.
+ initiateGarbageCollection(delay = 5.seconds)
+
return AuthenticationResult.SUCCEEDED
}
@@ -312,6 +324,15 @@
}
}
+ private suspend fun initiateGarbageCollection(delay: Duration) {
+ applicationScope.launch(backgroundDispatcher) {
+ delay(delay)
+ System.gc()
+ System.runFinalization()
+ System.gc()
+ }
+ }
+
companion object {
const val TAG = "AuthenticationInteractor"
}
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModel.kt
index 8e14778..5c9c997 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/PasswordBouncerViewModel.kt
@@ -26,6 +26,7 @@
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.stateIn
+import kotlinx.coroutines.launch
/** Holds UI state and handles user input for the password bouncer UI. */
class PasswordBouncerViewModel(
@@ -48,9 +49,6 @@
override val lockoutMessageId = R.string.kg_too_many_failed_password_attempts_dialog_message
- /** Whether the input method editor (for example, the software keyboard) is visible. */
- private var isImeVisible: Boolean = false
-
/** Whether the text field element currently has focus. */
private val isTextFieldFocused = MutableStateFlow(false)
@@ -65,7 +63,6 @@
override fun onHidden() {
super.onHidden()
- isImeVisible = false
isTextFieldFocused.value = false
}
@@ -97,16 +94,9 @@
}
}
- /**
- * Notifies that the input method editor (for example, the software keyboard) has been shown or
- * hidden.
- */
- suspend fun onImeVisibilityChanged(isVisible: Boolean) {
- if (isImeVisible && !isVisible && isInputEnabled.value) {
- interactor.onImeHiddenByUser()
- }
-
- isImeVisible = isVisible
+ /** Notifies that the user has dismissed the software keyboard (IME). */
+ fun onImeDismissed() {
+ viewModelScope.launch { interactor.onImeHiddenByUser() }
}
/** Notifies that the password text field has gained or lost focus. */
diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt
index 28adb77..80fee64 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt
@@ -33,7 +33,6 @@
import com.android.systemui.communal.widgets.EditWidgetsActivityStarter
import com.android.systemui.communal.widgets.WidgetConfigurator
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.smartspace.data.repository.SmartspaceRepository
import com.android.systemui.user.data.repository.UserRepository
@@ -41,11 +40,9 @@
import com.android.systemui.util.kotlin.BooleanFlowOperators.not
import com.android.systemui.util.kotlin.BooleanFlowOperators.or
import javax.inject.Inject
-import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.combine
@@ -53,7 +50,6 @@
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
-import kotlinx.coroutines.flow.stateIn
/** Encapsulates business-logic related to communal mode. */
@OptIn(ExperimentalCoroutinesApi::class)
@@ -61,7 +57,6 @@
class CommunalInteractor
@Inject
constructor(
- @Application applicationScope: CoroutineScope,
private val communalRepository: CommunalRepository,
private val widgetRepository: CommunalWidgetRepository,
private val communalPrefsRepository: CommunalPrefsRepository,
@@ -81,30 +76,15 @@
val isCommunalEnabled: Boolean
get() = communalRepository.isCommunalEnabled
- /** A {@link StateFlow} that tracks whether communal features are enabled. */
- val communalEnabledState: StateFlow<Boolean>
- get() = communalRepository.communalEnabledState
-
/** Whether communal features are enabled and available. */
- val isCommunalAvailable: StateFlow<Boolean> =
- flowOf(isCommunalEnabled)
- .flatMapLatest { enabled ->
- if (enabled) {
- val isMainUser = userRepository.selectedUserInfo.map { it.isMain }
- and(
- isMainUser,
- not(keyguardInteractor.isEncryptedOrLockdown),
- or(keyguardInteractor.isKeyguardVisible, keyguardInteractor.isDreaming),
- )
- } else {
- flowOf(false)
- }
- }
- .stateIn(
- scope = applicationScope,
- started = SharingStarted.WhileSubscribed(),
- initialValue = false,
+ val isCommunalAvailable: Flow<Boolean> =
+ and(
+ communalRepository.communalEnabledState,
+ userRepository.selectedUserInfo.map { it.isMain },
+ not(keyguardInteractor.isEncryptedOrLockdown),
+ or(keyguardInteractor.isKeyguardVisible, keyguardInteractor.isDreaming)
)
+ .distinctUntilChanged()
/**
* Target scene as requested by the underlying [SceneTransitionLayout] or through
@@ -176,8 +156,8 @@
}
/** Show the widget editor Activity. */
- fun showWidgetEditor() {
- editWidgetsActivityStarter.startActivity()
+ fun showWidgetEditor(preselectedKey: String? = null) {
+ editWidgetsActivityStarter.startActivity(preselectedKey)
}
/** Dismiss the CTA tile from the hub in view mode. */
diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/model/CommunalContentModel.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/model/CommunalContentModel.kt
index acd6cb0..ae019a1 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/domain/model/CommunalContentModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/domain/model/CommunalContentModel.kt
@@ -128,4 +128,6 @@
}
}
}
+
+ fun isWidget() = this is Widget
}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/BaseCommunalViewModel.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/BaseCommunalViewModel.kt
index 1e64d3f..a87ebd7 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/BaseCommunalViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/BaseCommunalViewModel.kt
@@ -33,18 +33,16 @@
private val communalInteractor: CommunalInteractor,
val mediaHost: MediaHost,
) {
- val isCommunalAvailable: StateFlow<Boolean> = communalInteractor.isCommunalAvailable
-
val currentScene: StateFlow<CommunalSceneKey> = communalInteractor.desiredScene
/** Whether widgets are currently being re-ordered. */
open val reorderingWidgets: StateFlow<Boolean> = MutableStateFlow(false)
- private val _selectedIndex: MutableStateFlow<Int?> = MutableStateFlow(null)
+ private val _selectedKey: MutableStateFlow<String?> = MutableStateFlow(null)
- /** The index of the currently selected item, or null if no item selected. */
- val selectedIndex: StateFlow<Int?>
- get() = _selectedIndex
+ /** The key of the currently selected item, or null if no item selected. */
+ val selectedKey: StateFlow<String?>
+ get() = _selectedKey
fun onSceneChanged(scene: CommunalSceneKey) {
communalInteractor.onSceneChanged(scene)
@@ -94,8 +92,8 @@
*/
open fun onReorderWidgets(widgetIdToPriorityMap: Map<Int, Int>) {}
- /** Called as the UI requests opening the widget editor. */
- open fun onOpenWidgetEditor() {}
+ /** Called as the UI requests opening the widget editor with an optional preselected widget. */
+ open fun onOpenWidgetEditor(preselectedKey: String? = null) {}
/** Called as the UI requests to dismiss the CTA tile. */
open fun onDismissCtaTile() {}
@@ -109,8 +107,8 @@
/** Called as the user cancels dragging a widget to reorder. */
open fun onReorderWidgetCancel() {}
- /** Set the index of the currently selected item */
- fun setSelectedIndex(index: Int?) {
- _selectedIndex.value = index
+ /** Set the key of the currently selected item */
+ fun setSelectedKey(key: String?) {
+ _selectedKey.value = key
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalEditModeViewModel.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalEditModeViewModel.kt
index 4b98f1a..ebcfb8b 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalEditModeViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalEditModeViewModel.kt
@@ -29,7 +29,6 @@
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.map
-import kotlinx.coroutines.flow.onEach
/** The view model for communal hub in edit mode. */
@SysUISingleton
@@ -44,10 +43,9 @@
// Only widgets are editable. The CTA tile comes last in the list and remains visible.
override val communalContent: Flow<List<CommunalContentModel>> =
- communalInteractor.widgetContent
- // Clear the selected index when the list is updated.
- .onEach { setSelectedIndex(null) }
- .map { widgets -> widgets + listOf(CommunalContentModel.CtaTileInEditMode()) }
+ communalInteractor.widgetContent.map { widgets ->
+ widgets + listOf(CommunalContentModel.CtaTileInEditMode())
+ }
private val _reorderingWidgets = MutableStateFlow(false)
@@ -61,7 +59,7 @@
override fun onReorderWidgetStart() {
// Clear selection status
- setSelectedIndex(null)
+ setSelectedKey(null)
_reorderingWidgets.value = true
uiEventLogger.log(CommunalUiEvent.COMMUNAL_HUB_REORDER_WIDGET_START)
}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt
index a909383..d7a3705 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt
@@ -81,7 +81,8 @@
}
}
- override fun onOpenWidgetEditor() = communalInteractor.showWidgetEditor()
+ override fun onOpenWidgetEditor(preselectedKey: String?) =
+ communalInteractor.showWidgetEditor(preselectedKey)
override fun onDismissCtaTile() {
scope.launch {
diff --git a/packages/SystemUI/src/com/android/systemui/communal/widgets/EditWidgetsActivity.kt b/packages/SystemUI/src/com/android/systemui/communal/widgets/EditWidgetsActivity.kt
index a257543..ad1327e 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/widgets/EditWidgetsActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/widgets/EditWidgetsActivity.kt
@@ -47,6 +47,7 @@
private const val EXTRA_FILTER_STRATEGY = "filter_strategy"
private const val FILTER_STRATEGY_GLANCEABLE_HUB = 1
private const val TAG = "EditWidgetsActivity"
+ const val EXTRA_PRESELECTED_KEY = "preselected_key"
}
private val widgetConfigurator by lazy { widgetConfiguratorFactory.create(this) }
@@ -92,6 +93,9 @@
windowInsetsController?.hide(WindowInsets.Type.systemBars())
window.setDecorFitsSystemWindows(false)
+ val preselectedKey = intent.getStringExtra(EXTRA_PRESELECTED_KEY)
+ communalViewModel.setSelectedKey(preselectedKey)
+
setCommunalEditWidgetActivityContent(
activity = this,
viewModel = communalViewModel,
diff --git a/packages/SystemUI/src/com/android/systemui/communal/widgets/EditWidgetsActivityStarter.kt b/packages/SystemUI/src/com/android/systemui/communal/widgets/EditWidgetsActivityStarter.kt
index 55acad0..d1843af 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/widgets/EditWidgetsActivityStarter.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/widgets/EditWidgetsActivityStarter.kt
@@ -18,12 +18,13 @@
import android.content.Context
import android.content.Intent
+import com.android.systemui.communal.widgets.EditWidgetsActivity.Companion.EXTRA_PRESELECTED_KEY
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.plugins.ActivityStarter
import javax.inject.Inject
interface EditWidgetsActivityStarter {
- fun startActivity()
+ fun startActivity(preselectedKey: String? = null)
}
class EditWidgetsActivityStarterImpl
@@ -33,10 +34,11 @@
private val activityStarter: ActivityStarter,
) : EditWidgetsActivityStarter {
- override fun startActivity() {
+ override fun startActivity(preselectedKey: String?) {
activityStarter.startActivityDismissingKeyguard(
Intent(applicationContext, EditWidgetsActivity::class.java)
- .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK),
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)
+ .apply { preselectedKey?.let { putExtra(EXTRA_PRESELECTED_KEY, preselectedKey) } },
/* onlyProvisioned = */ true,
/* dismissShade = */ true,
)
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/GlobalModule.java b/packages/SystemUI/src/com/android/systemui/dagger/GlobalModule.java
index 5c38264..3072f74 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/GlobalModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/GlobalModule.java
@@ -24,6 +24,7 @@
import com.android.systemui.plugins.PluginsModule;
import com.android.systemui.unfold.UnfoldTransitionModule;
import com.android.systemui.util.concurrency.GlobalConcurrencyModule;
+import com.android.systemui.util.kotlin.GlobalCoroutinesModule;
import dagger.Module;
import dagger.Provides;
@@ -47,6 +48,7 @@
AndroidInternalsModule.class,
FrameworkServicesModule.class,
GlobalConcurrencyModule.class,
+ GlobalCoroutinesModule.class,
UnfoldTransitionModule.class,
PluginsModule.class,
})
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java
index 50f861f..e9d1e94 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java
@@ -63,6 +63,7 @@
import com.android.systemui.statusbar.policy.SensorPrivacyController;
import com.android.systemui.statusbar.policy.SensorPrivacyControllerImpl;
import com.android.systemui.toast.ToastModule;
+import com.android.systemui.unfold.UnfoldTransitionModule;
import com.android.systemui.volume.dagger.VolumeModule;
import com.android.systemui.wallpapers.dagger.WallpaperModule;
@@ -107,6 +108,7 @@
ShadeModule.class,
StartCentralSurfacesModule.class,
SceneContainerFrameworkModule.class,
+ UnfoldTransitionModule.Startables.class,
ToastModule.class,
VolumeModule.class,
WallpaperModule.class
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index 92300ef..2587e2d 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -66,6 +66,7 @@
import com.android.systemui.log.table.TableLogBuffer;
import com.android.systemui.mediaprojection.appselector.MediaProjectionModule;
import com.android.systemui.mediaprojection.taskswitcher.MediaProjectionTaskSwitcherModule;
+import com.android.systemui.model.SceneContainerPlugin;
import com.android.systemui.model.SysUiState;
import com.android.systemui.motiontool.MotionToolModule;
import com.android.systemui.navigationbar.NavigationBarComponent;
@@ -133,7 +134,7 @@
import com.android.systemui.util.EventLogModule;
import com.android.systemui.util.concurrency.SysUIConcurrencyModule;
import com.android.systemui.util.dagger.UtilModule;
-import com.android.systemui.util.kotlin.CoroutinesModule;
+import com.android.systemui.util.kotlin.SysUICoroutinesModule;
import com.android.systemui.util.reference.ReferenceModule;
import com.android.systemui.util.sensors.SensorModule;
import com.android.systemui.util.settings.SettingsUtilModule;
@@ -182,7 +183,6 @@
ConfigurationControllerModule.class,
ConnectivityModule.class,
ControlsModule.class,
- CoroutinesModule.class,
DemoModeModule.class,
DeviceEntryModule.class,
DisableFlagsModule.class,
@@ -228,6 +228,7 @@
StatusBarWindowModule.class,
SystemPropertiesFlagsModule.class,
SysUIConcurrencyModule.class,
+ SysUICoroutinesModule.class,
SysUIUnfoldModule.class,
TelephonyRepositoryModule.class,
TemporaryDisplayModule.class,
@@ -268,8 +269,11 @@
@SysUISingleton
@Provides
- static SysUiState provideSysUiState(DisplayTracker displayTracker, DumpManager dumpManager) {
- final SysUiState state = new SysUiState(displayTracker);
+ static SysUiState provideSysUiState(
+ DisplayTracker displayTracker,
+ DumpManager dumpManager,
+ SceneContainerPlugin sceneContainerPlugin) {
+ final SysUiState state = new SysUiState(displayTracker, sceneContainerPlugin);
dumpManager.registerDumpable(state);
return state;
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/BluetoothDialog.java b/packages/SystemUI/src/com/android/systemui/keyboard/BluetoothDialog.java
deleted file mode 100644
index 5deea9b..0000000
--- a/packages/SystemUI/src/com/android/systemui/keyboard/BluetoothDialog.java
+++ /dev/null
@@ -1,32 +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.systemui.keyboard;
-
-import android.content.Context;
-import android.view.WindowManager;
-
-import com.android.systemui.statusbar.phone.SystemUIDialog;
-
-public class BluetoothDialog extends SystemUIDialog {
-
- public BluetoothDialog(Context context) {
- super(context);
-
- getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG);
- setShowForAllUsers(true);
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/BluetoothDialogDelegate.java b/packages/SystemUI/src/com/android/systemui/keyboard/BluetoothDialogDelegate.java
new file mode 100644
index 0000000..98642d7
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/BluetoothDialogDelegate.java
@@ -0,0 +1,40 @@
+/*
+ * 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.systemui.keyboard;
+
+import android.view.WindowManager;
+
+import com.android.systemui.statusbar.phone.SystemUIDialog;
+
+import javax.inject.Inject;
+
+public class BluetoothDialogDelegate implements SystemUIDialog.Delegate{
+
+ private final SystemUIDialog.Factory mSystemUIDialogFactory;
+ @Inject
+ public BluetoothDialogDelegate(SystemUIDialog.Factory systemUIDialogFactory) {
+ mSystemUIDialogFactory = systemUIDialogFactory;
+ }
+
+ @Override
+ public SystemUIDialog createDialog() {
+ SystemUIDialog dialog = mSystemUIDialogFactory.create(this);
+ dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG);
+ dialog.setShowForAllUsers(true);
+ return dialog;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/KeyboardUI.java b/packages/SystemUI/src/com/android/systemui/keyboard/KeyboardUI.java
index 1cdbe6f..17e3ca6 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/KeyboardUI.java
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/KeyboardUI.java
@@ -52,6 +52,7 @@
import com.android.systemui.CoreStartable;
import com.android.systemui.res.R;
import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.statusbar.phone.SystemUIDialog;
import com.android.systemui.util.settings.SecureSettings;
import java.io.PrintWriter;
@@ -109,6 +110,7 @@
private final Provider<LocalBluetoothManager> mBluetoothManagerProvider;
private final SecureSettings mSecureSettings;
+ private final BluetoothDialogDelegate mBluetoothDialogDelegate;
private boolean mEnabled;
private String mKeyboardName;
@@ -121,16 +123,20 @@
private int mInTabletMode = InputManager.SWITCH_STATE_UNKNOWN;
private int mScanAttempt = 0;
private ScanCallback mScanCallback;
- private BluetoothDialog mDialog;
+ private SystemUIDialog mDialog;
private int mState;
@Inject
- public KeyboardUI(Context context, Provider<LocalBluetoothManager> bluetoothManagerProvider,
- SecureSettings secureSettings) {
+ public KeyboardUI(
+ Context context,
+ Provider<LocalBluetoothManager> bluetoothManagerProvider,
+ SecureSettings secureSettings,
+ BluetoothDialogDelegate bluetoothDialogDelegate) {
mContext = context;
this.mBluetoothManagerProvider = bluetoothManagerProvider;
mSecureSettings = secureSettings;
+ mBluetoothDialogDelegate = bluetoothDialogDelegate;
}
@Override
@@ -437,7 +443,7 @@
new BluetoothDialogClickListener();
DialogInterface.OnDismissListener dismissListener =
new BluetoothDialogDismissListener();
- mDialog = new BluetoothDialog(mContext);
+ mDialog = mBluetoothDialogDelegate.createDialog();
mDialog.setTitle(R.string.enable_bluetooth_title);
mDialog.setMessage(R.string.enable_bluetooth_message);
mDialog.setPositiveButton(
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/stickykeys/StickyKeysLogger.kt b/packages/SystemUI/src/com/android/systemui/keyboard/stickykeys/StickyKeysLogger.kt
index 4ed8120..5ef5ef1 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/stickykeys/StickyKeysLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/stickykeys/StickyKeysLogger.kt
@@ -43,4 +43,13 @@
{ "new sticky keys state received: $str1" }
)
}
-}
\ No newline at end of file
+
+ fun logNewSettingValue(enabled: Boolean) {
+ buffer.log(
+ TAG,
+ LogLevel.INFO,
+ { bool1 = enabled },
+ { "sticky key setting changed, new state: ${if (bool1) "enabled" else "disabled"}" }
+ )
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/stickykeys/data/repository/StickyKeysRepository.kt b/packages/SystemUI/src/com/android/systemui/keyboard/stickykeys/data/repository/StickyKeysRepository.kt
index 34d2888..ec29bd6 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/stickykeys/data/repository/StickyKeysRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/stickykeys/data/repository/StickyKeysRepository.kt
@@ -19,8 +19,10 @@
import android.hardware.input.InputManager
import android.hardware.input.InputManager.StickyModifierStateListener
import android.hardware.input.StickyModifierState
+import android.provider.Settings
import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
+import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.keyboard.stickykeys.StickyKeysLogger
import com.android.systemui.keyboard.stickykeys.shared.model.Locked
@@ -30,14 +32,19 @@
import com.android.systemui.keyboard.stickykeys.shared.model.ModifierKey.CTRL
import com.android.systemui.keyboard.stickykeys.shared.model.ModifierKey.META
import com.android.systemui.keyboard.stickykeys.shared.model.ModifierKey.SHIFT
+import com.android.systemui.user.data.repository.UserRepository
+import com.android.systemui.util.settings.SecureSettings
+import com.android.systemui.util.settings.SettingsProxyExt.observerFlow
import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.flow.onStart
import javax.inject.Inject
interface StickyKeysRepository {
@@ -45,11 +52,15 @@
val settingEnabled: Flow<Boolean>
}
+@SysUISingleton
+@OptIn(ExperimentalCoroutinesApi::class)
class StickyKeysRepositoryImpl
@Inject
constructor(
private val inputManager: InputManager,
@Background private val backgroundDispatcher: CoroutineDispatcher,
+ private val secureSettings: SecureSettings,
+ userRepository: UserRepository,
private val stickyKeysLogger: StickyKeysLogger,
) : StickyKeysRepository {
@@ -66,8 +77,26 @@
.onEach { stickyKeysLogger.logNewStickyKeysReceived(it) }
.flowOn(backgroundDispatcher)
- // TODO(b/319837892): Implement reading actual setting
- override val settingEnabled: StateFlow<Boolean> = MutableStateFlow(true)
+ override val settingEnabled: Flow<Boolean> =
+ userRepository.selectedUserInfo
+ .flatMapLatest { stickyKeySettingObserver(it.id) }
+ .flowOn(backgroundDispatcher)
+
+ private fun stickyKeySettingObserver(userId: Int): Flow<Boolean> {
+ return secureSettings
+ .observerFlow(userId, SETTING_KEY)
+ .onStart { emit(Unit) }
+ .map { isSettingEnabledForCurrentUser(userId) }
+ .distinctUntilChanged()
+ .onEach { stickyKeysLogger.logNewSettingValue(it) }
+ }
+
+ private fun isSettingEnabledForCurrentUser(userId: Int) =
+ secureSettings.getIntForUser(
+ /* name= */ SETTING_KEY,
+ /* default= */ 0,
+ /* userHandle= */ userId
+ ) != 0
private fun toStickyKeysMap(state: StickyModifierState): LinkedHashMap<ModifierKey, Locked> {
val keys = linkedMapOf<ModifierKey, Locked>()
@@ -88,5 +117,6 @@
companion object {
const val TAG = "StickyKeysRepositoryImpl"
+ const val SETTING_KEY = Settings.Secure.ACCESSIBILITY_STICKY_KEYS
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 8e3b196..794befa 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -2184,6 +2184,10 @@
*/
public void showDismissibleKeyguard() {
if (mFoldGracePeriodProvider.isEnabled()) {
+ if (!mUpdateMonitor.isDeviceProvisioned()) {
+ Log.d(TAG, "Device not provisioned, so ignore request to show keyguard.");
+ return;
+ }
Bundle showKeyguardUnlocked = new Bundle();
showKeyguardUnlocked.putBoolean(OPTION_SHOW_DISMISSIBLE, true);
showKeyguard(showKeyguardUnlocked);
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
index 1c6056c..64e2870 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
@@ -567,17 +567,17 @@
val callback =
object : KeyguardUpdateMonitorCallback() {
override fun onStrongAuthStateChanged(userId: Int) {
- trySend(userId)
+ trySendWithFailureLogging(userId, TAG, "strong auth state change")
}
}
-
keyguardUpdateMonitor.registerCallback(callback)
-
awaitClose { keyguardUpdateMonitor.removeCallback(callback) }
}
.filter { userId -> userId == userTracker.userId }
.onStart { emit(userTracker.userId) }
.mapLatest { userId -> keyguardUpdateMonitor.isEncryptedOrLockdown(userId) }
+ // KeyguardUpdateMonitor#registerCallback needs to be called on the main thread.
+ .flowOn(mainDispatcher)
override fun isKeyguardShowing(): Boolean {
return keyguardStateController.isShowing
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt
index 3888345..a1f9425 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt
@@ -56,6 +56,7 @@
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
@@ -102,10 +103,10 @@
quickAffordanceAlwaysVisible(position),
keyguardInteractor.isDozing,
keyguardInteractor.isKeyguardShowing,
- shadeInteractor.anyExpansion,
+ shadeInteractor.anyExpansion.map { it < 1.0f }.distinctUntilChanged(),
biometricSettingsRepository.isCurrentUserInLockdown,
- ) { affordance, isDozing, isKeyguardShowing, qsExpansion, isUserInLockdown ->
- if (!isDozing && isKeyguardShowing && (qsExpansion < 1.0f) && !isUserInLockdown) {
+ ) { affordance, isDozing, isKeyguardShowing, isQuickSettingsVisible, isUserInLockdown ->
+ if (!isDozing && isKeyguardShowing && isQuickSettingsVisible && !isUserInLockdown) {
affordance
} else {
KeyguardQuickAffordanceModel.Hidden
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/PreviewKeyguardBlueprintViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/PreviewKeyguardBlueprintViewBinder.kt
deleted file mode 100644
index 2feaa2e..0000000
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/PreviewKeyguardBlueprintViewBinder.kt
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-package com.android.systemui.keyguard.ui.binder
-
-import android.os.Trace
-import androidx.constraintlayout.widget.ConstraintLayout
-import androidx.constraintlayout.widget.ConstraintSet
-import androidx.lifecycle.Lifecycle
-import androidx.lifecycle.repeatOnLifecycle
-import com.android.systemui.keyguard.ui.viewmodel.KeyguardBlueprintViewModel
-import com.android.systemui.lifecycle.repeatWhenAttached
-import kotlinx.coroutines.DisposableHandle
-import kotlinx.coroutines.launch
-
-/**
- * Binds the existing blueprint to the constraint layout that previews keyguard.
- *
- * This view binder should only inflate and add relevant views and apply the constraints. Actual
- * data binding should be done in {@link KeyguardPreviewRenderer}
- */
-class PreviewKeyguardBlueprintViewBinder {
- companion object {
-
- /**
- * Binds the existing blueprint to the constraint layout that previews keyguard.
- *
- * @param constraintLayout The root view to bind to
- * @param viewModel The instance of the view model that contains flows we collect on.
- * @param finishedAddViewCallback Called when we have finished inflating the views.
- */
- fun bind(
- constraintLayout: ConstraintLayout,
- viewModel: KeyguardBlueprintViewModel,
- finishedAddViewCallback: () -> Unit
- ): DisposableHandle {
- return constraintLayout.repeatWhenAttached {
- repeatOnLifecycle(Lifecycle.State.CREATED) {
- launch {
- viewModel.blueprint.collect { blueprint ->
- val prevBluePrint = viewModel.currentBluePrint
- Trace.beginSection("PreviewKeyguardBlueprint#applyBlueprint")
-
- ConstraintSet().apply {
- clone(constraintLayout)
- val emptyLayout = ConstraintSet.Layout()
- knownIds.forEach { getConstraint(it).layout.copyFrom(emptyLayout) }
- blueprint.applyConstraints(this)
- // Add and remove views of sections that are not contained by the
- // other.
- blueprint.replaceViews(
- prevBluePrint,
- constraintLayout,
- bindData = false
- )
- applyTo(constraintLayout)
- }
-
- viewModel.currentBluePrint = blueprint
- finishedAddViewCallback.invoke()
- Trace.endSection()
- }
- }
- }
- }
- }
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt
index 841bad4..a0c0095 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/preview/KeyguardPreviewRenderer.kt
@@ -41,6 +41,7 @@
import android.widget.FrameLayout
import android.widget.TextView
import androidx.constraintlayout.widget.ConstraintLayout
+import androidx.constraintlayout.widget.ConstraintSet
import androidx.core.view.isInvisible
import com.android.keyguard.ClockEventController
import com.android.keyguard.KeyguardClockSwitch
@@ -54,15 +55,12 @@
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
-import com.android.systemui.flags.FeatureFlagsClassic
-import com.android.systemui.keyguard.shared.KeyguardShadeMigrationNssl
import com.android.systemui.keyguard.ui.binder.KeyguardPreviewClockViewBinder
import com.android.systemui.keyguard.ui.binder.KeyguardPreviewSmartspaceViewBinder
import com.android.systemui.keyguard.ui.binder.KeyguardQuickAffordanceViewBinder
import com.android.systemui.keyguard.ui.binder.KeyguardRootViewBinder
-import com.android.systemui.keyguard.ui.binder.PreviewKeyguardBlueprintViewBinder
import com.android.systemui.keyguard.ui.view.KeyguardRootView
-import com.android.systemui.keyguard.ui.viewmodel.KeyguardBlueprintViewModel
+import com.android.systemui.keyguard.ui.view.layout.sections.DefaultShortcutsSection
import com.android.systemui.keyguard.ui.viewmodel.KeyguardBottomAreaViewModel
import com.android.systemui.keyguard.ui.viewmodel.KeyguardPreviewClockViewModel
import com.android.systemui.keyguard.ui.viewmodel.KeyguardPreviewSmartspaceViewModel
@@ -124,19 +122,18 @@
private val broadcastDispatcher: BroadcastDispatcher,
private val lockscreenSmartspaceController: LockscreenSmartspaceController,
private val udfpsOverlayInteractor: UdfpsOverlayInteractor,
- private val featureFlags: FeatureFlagsClassic,
private val falsingManager: FalsingManager,
private val vibratorHelper: VibratorHelper,
private val indicationController: KeyguardIndicationController,
private val keyguardRootViewModel: KeyguardRootViewModel,
@Assisted bundle: Bundle,
- private val keyguardBlueprintViewModel: KeyguardBlueprintViewModel,
private val occludingAppDeviceEntryMessageViewModel: OccludingAppDeviceEntryMessageViewModel,
private val chipbarCoordinator: ChipbarCoordinator,
private val screenOffAnimationController: ScreenOffAnimationController,
private val shadeInteractor: ShadeInteractor,
private val secureSettings: SecureSettings,
private val communalTutorialViewModel: CommunalTutorialIndicatorViewModel,
+ private val defaultShortcutsSection: DefaultShortcutsSection,
) {
val hostToken: IBinder? = bundle.getBinder(KEY_HOST_TOKEN)
private val width: Int = bundle.getInt(KEY_VIEW_WIDTH)
@@ -393,32 +390,32 @@
setUpUdfps(previewContext, rootView)
- disposables.add(
- PreviewKeyguardBlueprintViewBinder.bind(keyguardRootView, keyguardBlueprintViewModel) {
- if (keyguardBottomAreaRefactor()) {
- setupShortcuts(keyguardRootView)
- }
+ if (keyguardBottomAreaRefactor()) {
+ setupShortcuts(keyguardRootView)
+ }
- if (!shouldHideClock) {
- setUpClock(previewContext, rootView)
- KeyguardPreviewClockViewBinder.bind(
- largeClockHostView,
- smallClockHostView,
- clockViewModel,
- )
- }
+ if (!shouldHideClock) {
+ setUpClock(previewContext, rootView)
+ KeyguardPreviewClockViewBinder.bind(
+ largeClockHostView,
+ smallClockHostView,
+ clockViewModel,
+ )
+ }
- setUpSmartspace(previewContext, rootView)
- smartSpaceView?.let {
- KeyguardPreviewSmartspaceViewBinder.bind(it, smartspaceViewModel)
- }
-
- setupCommunalTutorialIndicator(keyguardRootView)
- }
- )
+ setUpSmartspace(previewContext, rootView)
+ smartSpaceView?.let { KeyguardPreviewSmartspaceViewBinder.bind(it, smartspaceViewModel) }
+ setupCommunalTutorialIndicator(keyguardRootView)
}
private fun setupShortcuts(keyguardRootView: ConstraintLayout) {
+ // Add shortcuts
+ val cs = ConstraintSet()
+ cs.clone(keyguardRootView)
+ defaultShortcutsSection.addViews(keyguardRootView)
+ defaultShortcutsSection.applyConstraints(cs)
+ cs.applyTo(keyguardRootView)
+
keyguardRootView.findViewById<LaunchableImageView?>(R.id.start_button)?.let { imageView ->
shortcutsBindings.add(
KeyguardQuickAffordanceViewBinder.bind(
@@ -476,53 +473,40 @@
}
private fun setUpClock(previewContext: Context, parentView: ViewGroup) {
- largeClockHostView =
- if (KeyguardShadeMigrationNssl.isEnabled) {
- parentView.requireViewById<FrameLayout>(R.id.lockscreen_clock_view_large)
- } else {
- val hostView = FrameLayout(previewContext)
- hostView.layoutParams =
- FrameLayout.LayoutParams(
- FrameLayout.LayoutParams.MATCH_PARENT,
- FrameLayout.LayoutParams.MATCH_PARENT,
- )
- parentView.addView(hostView)
- hostView
- }
+ val resources = parentView.resources
+ largeClockHostView = FrameLayout(previewContext)
+ largeClockHostView.layoutParams =
+ FrameLayout.LayoutParams(
+ FrameLayout.LayoutParams.MATCH_PARENT,
+ FrameLayout.LayoutParams.MATCH_PARENT,
+ )
+ parentView.addView(largeClockHostView)
largeClockHostView.isInvisible = true
- smallClockHostView =
- if (KeyguardShadeMigrationNssl.isEnabled) {
- parentView.requireViewById<FrameLayout>(R.id.lockscreen_clock_view)
- } else {
- val resources = parentView.resources
- val hostView = FrameLayout(previewContext)
- val layoutParams =
- FrameLayout.LayoutParams(
- FrameLayout.LayoutParams.WRAP_CONTENT,
- resources.getDimensionPixelSize(
- com.android.systemui.customization.R.dimen.small_clock_height
- )
- )
- layoutParams.topMargin =
- KeyguardPreviewSmartspaceViewModel.getStatusBarHeight(resources) +
- resources.getDimensionPixelSize(
- com.android.systemui.customization.R.dimen.small_clock_padding_top
- )
- hostView.layoutParams = layoutParams
-
- hostView.setPaddingRelative(
- resources.getDimensionPixelSize(
- com.android.systemui.customization.R.dimen.clock_padding_start
- ),
- 0,
- 0,
- 0
+ smallClockHostView = FrameLayout(previewContext)
+ val layoutParams =
+ FrameLayout.LayoutParams(
+ FrameLayout.LayoutParams.WRAP_CONTENT,
+ resources.getDimensionPixelSize(
+ com.android.systemui.customization.R.dimen.small_clock_height
)
- hostView.clipChildren = false
- parentView.addView(hostView)
- hostView
- }
+ )
+ layoutParams.topMargin =
+ KeyguardPreviewSmartspaceViewModel.getStatusBarHeight(resources) +
+ resources.getDimensionPixelSize(
+ com.android.systemui.customization.R.dimen.small_clock_padding_top
+ )
+ smallClockHostView.layoutParams = layoutParams
+ smallClockHostView.setPaddingRelative(
+ resources.getDimensionPixelSize(
+ com.android.systemui.customization.R.dimen.clock_padding_start
+ ),
+ 0,
+ 0,
+ 0
+ )
+ smallClockHostView.clipChildren = false
+ parentView.addView(smallClockHostView)
smallClockHostView.isInvisible = true
// TODO (b/283465254): Move the listeners to KeyguardClockRepository
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/MediaProjectionCaptureTarget.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/MediaProjectionCaptureTarget.kt
index 11d0be5..a618490 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/MediaProjectionCaptureTarget.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/MediaProjectionCaptureTarget.kt
@@ -16,7 +16,7 @@
package com.android.systemui.mediaprojection
-import android.os.IBinder
+import android.app.ActivityOptions.LaunchCookie
import android.os.Parcel
import android.os.Parcelable
@@ -24,12 +24,12 @@
* Class that represents an area that should be captured. Currently it has only a launch cookie that
* represents a task but we potentially could add more identifiers e.g. for a pair of tasks.
*/
-data class MediaProjectionCaptureTarget(val launchCookie: IBinder?) : Parcelable {
+data class MediaProjectionCaptureTarget(val launchCookie: LaunchCookie?) : Parcelable {
- constructor(parcel: Parcel) : this(parcel.readStrongBinder())
+ constructor(parcel: Parcel) : this(LaunchCookie.readFromParcel(parcel))
override fun writeToParcel(dest: Parcel, flags: Int) {
- dest.writeStrongBinder(launchCookie)
+ LaunchCookie.writeToParcel(launchCookie, dest)
}
override fun describeContents(): Int = 0
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorActivity.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorActivity.kt
index 50e9e751..4685c5a 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorActivity.kt
@@ -16,6 +16,7 @@
package com.android.systemui.mediaprojection.appselector
import android.app.ActivityOptions
+import android.app.ActivityOptions.LaunchCookie
import android.content.Intent
import android.content.res.Configuration
import android.content.res.Resources
@@ -24,9 +25,7 @@
import android.media.projection.MediaProjectionManager.EXTRA_MEDIA_PROJECTION
import android.media.projection.ReviewGrantedConsentResult.RECORD_CANCEL
import android.media.projection.ReviewGrantedConsentResult.RECORD_CONTENT_TASK
-import android.os.Binder
import android.os.Bundle
-import android.os.IBinder
import android.os.ResultReceiver
import android.os.UserHandle
import android.util.Log
@@ -163,9 +162,9 @@
val intent = createIntent(targetInfo)
- val launchToken: IBinder = Binder("media_projection_launch_token")
+ val launchCookie = LaunchCookie("media_projection_launch_token")
val activityOptions = ActivityOptions.makeBasic()
- activityOptions.launchCookie = launchToken
+ activityOptions.setLaunchCookie(launchCookie)
val userHandle = mMultiProfilePagerAdapter.activeListAdapter.userHandle
@@ -175,7 +174,7 @@
// is created and ready to be captured.
val activityStarted =
activityLauncher.startActivityAsUser(intent, userHandle, activityOptions.toBundle()) {
- returnSelectedApp(launchToken)
+ returnSelectedApp(launchCookie)
}
// Rely on the ActivityManager to pop up a dialog regarding app suspension
@@ -233,7 +232,7 @@
}
}
- override fun returnSelectedApp(launchCookie: IBinder) {
+ override fun returnSelectedApp(launchCookie: LaunchCookie) {
taskSelected = true
if (intent.hasExtra(EXTRA_CAPTURE_REGION_RESULT_RECEIVER)) {
// The client requested to return the result in the result receiver instead of
@@ -255,7 +254,7 @@
val mediaProjectionBinder = intent.getIBinderExtra(EXTRA_MEDIA_PROJECTION)
val projection = IMediaProjection.Stub.asInterface(mediaProjectionBinder)
- projection.launchCookie = launchCookie
+ projection.setLaunchCookie(launchCookie)
val intent = Intent()
intent.putExtra(EXTRA_MEDIA_PROJECTION, projection.asBinder())
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorResultHandler.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorResultHandler.kt
index 93c3bce..f204b3e 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorResultHandler.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorResultHandler.kt
@@ -1,6 +1,6 @@
package com.android.systemui.mediaprojection.appselector
-import android.os.IBinder
+import android.app.ActivityOptions.LaunchCookie
/**
* Interface that allows to continue the media projection flow and return the selected app
@@ -11,5 +11,5 @@
* Return selected app to the original caller of the media projection app picker.
* @param launchCookie launch cookie of the launched activity of the target app
*/
- fun returnSelectedApp(launchCookie: IBinder)
+ fun returnSelectedApp(launchCookie: LaunchCookie)
}
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/MediaProjectionRecentsViewController.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/MediaProjectionRecentsViewController.kt
index ba837db..a811065 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/MediaProjectionRecentsViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/MediaProjectionRecentsViewController.kt
@@ -17,10 +17,10 @@
package com.android.systemui.mediaprojection.appselector.view
import android.app.ActivityOptions
+import android.app.ActivityOptions.LaunchCookie
import android.app.ComponentOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED
import android.app.IActivityTaskManager
import android.graphics.Rect
-import android.os.Binder
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
@@ -121,7 +121,7 @@
}
override fun onRecentAppClicked(task: RecentTask, view: View) {
- val launchCookie = Binder()
+ val launchCookie = LaunchCookie()
val activityOptions =
ActivityOptions.makeScaleUpAnimation(
view,
@@ -132,7 +132,7 @@
)
activityOptions.pendingIntentBackgroundActivityStartMode =
MODE_BACKGROUND_ACTIVITY_START_ALLOWED
- activityOptions.launchCookie = launchCookie
+ activityOptions.setLaunchCookie(launchCookie)
activityOptions.launchDisplayId = task.displayId
activityTaskManager.startActivityFromRecents(task.taskId, activityOptions.toBundle())
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java b/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java
index 039372d..8b034b2 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java
@@ -28,6 +28,7 @@
import android.annotation.Nullable;
import android.app.Activity;
import android.app.ActivityManager;
+import android.app.ActivityOptions.LaunchCookie;
import android.app.AlertDialog;
import android.app.StatusBarManager;
import android.content.Context;
@@ -146,6 +147,13 @@
final IMediaProjection projection =
MediaProjectionServiceHelper.createOrReuseProjection(mUid, mPackageName,
mReviewGrantedConsentRequired);
+
+ LaunchCookie launchCookie = launchingIntent.getParcelableExtra(
+ MediaProjectionManager.EXTRA_LAUNCH_COOKIE, LaunchCookie.class);
+ if (launchCookie != null) {
+ projection.setLaunchCookie(launchCookie);
+ }
+
// Automatically grant consent if a system-privileged component is recording.
final Intent intent = new Intent();
intent.putExtra(MediaProjectionManager.EXTRA_MEDIA_PROJECTION,
diff --git a/packages/SystemUI/src/com/android/systemui/model/SceneContainerPlugin.kt b/packages/SystemUI/src/com/android/systemui/model/SceneContainerPlugin.kt
new file mode 100644
index 0000000..6eb6226
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/model/SceneContainerPlugin.kt
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.model
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.scene.domain.interactor.SceneInteractor
+import com.android.systemui.scene.shared.flag.SceneContainerFlag
+import com.android.systemui.scene.shared.model.ObservableTransitionState
+import com.android.systemui.scene.shared.model.SceneKey
+import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BOUNCER_SHOWING
+import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED
+import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE
+import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_QUICK_SETTINGS_EXPANDED
+import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING
+import dagger.Lazy
+import javax.inject.Inject
+
+/**
+ * A plugin for [SysUiState] that provides overrides for certain state flags that must be pulled
+ * from the scene framework when that framework is enabled.
+ */
+@SysUISingleton
+class SceneContainerPlugin
+@Inject
+constructor(
+ private val interactor: Lazy<SceneInteractor>,
+) {
+ /**
+ * Returns an override value for the given [flag] or `null` if the scene framework isn't enabled
+ * or if the flag value doesn't need to be overridden.
+ */
+ fun flagValueOverride(flag: Int): Boolean? {
+ if (!SceneContainerFlag.isEnabled) {
+ return null
+ }
+
+ val transitionState = interactor.get().transitionState.value
+ val idleTransitionStateOrNull = transitionState as? ObservableTransitionState.Idle
+ val currentSceneOrNull = idleTransitionStateOrNull?.scene
+ return currentSceneOrNull?.let { sceneKey -> EvaluatorByFlag[flag]?.invoke(sceneKey) }
+ }
+
+ companion object {
+
+ /**
+ * Value evaluator function by state flag ID.
+ *
+ * The value evaluator function can be invoked, passing in the current [SceneKey] to know
+ * the override value of the flag ID.
+ *
+ * If the map doesn't contain an entry for a certain flag ID, it means that it doesn't need
+ * to be overridden by the scene framework.
+ */
+ val EvaluatorByFlag =
+ mapOf<Int, (SceneKey) -> Boolean>(
+ SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE to { it != SceneKey.Gone },
+ SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED to { it == SceneKey.Shade },
+ SYSUI_STATE_QUICK_SETTINGS_EXPANDED to { it == SceneKey.QuickSettings },
+ SYSUI_STATE_BOUNCER_SHOWING to { it == SceneKey.Bouncer },
+ SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING to { it == SceneKey.Lockscreen },
+ )
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/model/SysUiState.java b/packages/SystemUI/src/com/android/systemui/model/SysUiState.java
index 3cdcb2c..2dd2327 100644
--- a/packages/SystemUI/src/com/android/systemui/model/SysUiState.java
+++ b/packages/SystemUI/src/com/android/systemui/model/SysUiState.java
@@ -41,13 +41,15 @@
public static final boolean DEBUG = false;
private final DisplayTracker mDisplayTracker;
+ private final SceneContainerPlugin mSceneContainerPlugin;
private @QuickStepContract.SystemUiStateFlags int mFlags;
private final List<SysUiStateCallback> mCallbacks = new ArrayList<>();
private int mFlagsToSet = 0;
private int mFlagsToClear = 0;
- public SysUiState(DisplayTracker displayTracker) {
+ public SysUiState(DisplayTracker displayTracker, SceneContainerPlugin sceneContainerPlugin) {
mDisplayTracker = displayTracker;
+ mSceneContainerPlugin = sceneContainerPlugin;
}
/**
@@ -71,6 +73,16 @@
/** Methods to this call can be chained together before calling {@link #commitUpdate(int)}. */
public SysUiState setFlag(int flag, boolean enabled) {
+ final Boolean overrideOrNull = mSceneContainerPlugin.flagValueOverride(flag);
+ if (overrideOrNull != null && enabled != overrideOrNull) {
+ if (DEBUG) {
+ Log.d(TAG, "setFlag for flag " + flag + " and value " + enabled + " overridden to "
+ + overrideOrNull + " by scene container plugin");
+ }
+
+ enabled = overrideOrNull;
+ }
+
if (enabled) {
mFlagsToSet |= flag;
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavBarHelper.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavBarHelper.java
index d7e062f..7d13397 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavBarHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavBarHelper.java
@@ -41,6 +41,7 @@
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
+import android.os.Process;
import android.os.RemoteException;
import android.os.UserHandle;
import android.provider.Settings;
@@ -55,12 +56,14 @@
import androidx.annotation.NonNull;
+import com.android.internal.accessibility.common.ShortcutConstants;
import com.android.systemui.Dumpable;
import com.android.systemui.accessibility.AccessibilityButtonModeObserver;
import com.android.systemui.accessibility.AccessibilityButtonTargetsObserver;
import com.android.systemui.accessibility.SystemActions;
import com.android.systemui.assist.AssistManager;
import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.navigationbar.gestural.EdgeBackGestureHandler;
import com.android.systemui.recents.OverviewProxyService;
@@ -79,6 +82,7 @@
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
+import java.util.concurrent.Executor;
import javax.inject.Inject;
@@ -101,6 +105,7 @@
private static final String TAG = NavBarHelper.class.getSimpleName();
private final Handler mHandler = new Handler(Looper.getMainLooper());
+ private final Executor mMainExecutor;
private final AccessibilityManager mAccessibilityManager;
private final Lazy<AssistManager> mAssistManagerLazy;
private final Lazy<Optional<CentralSurfaces>> mCentralSurfacesOptionalLazy;
@@ -185,7 +190,12 @@
DisplayTracker displayTracker,
NotificationShadeWindowController notificationShadeWindowController,
DumpManager dumpManager,
- CommandQueue commandQueue) {
+ CommandQueue commandQueue,
+ @Main Executor mainExecutor) {
+ // b/319489709: This component shouldn't be running for a non-primary user
+ if (!Process.myUserHandle().equals(UserHandle.SYSTEM)) {
+ Log.wtf(TAG, "Unexpected initialization for non-primary user", new Throwable());
+ }
mContext = context;
mNotificationShadeWindowController = notificationShadeWindowController;
mCommandQueue = commandQueue;
@@ -201,6 +211,7 @@
mWm = wm;
mDefaultDisplayId = displayTracker.getDefaultDisplayId();
mEdgeBackGestureHandler = edgeBackGestureHandlerFactory.create(context);
+ mMainExecutor = mainExecutor;
mNavBarMode = navigationModeController.addListener(this);
mCommandQueue.addCallback(this);
@@ -370,7 +381,7 @@
// permission
final List<String> a11yButtonTargets =
mAccessibilityManager.getAccessibilityShortcutTargets(
- AccessibilityManager.ACCESSIBILITY_BUTTON);
+ ShortcutConstants.UserShortcutType.SOFTWARE);
final int requestingServices = a11yButtonTargets.size();
clickable = requestingServices >= 1;
@@ -418,7 +429,11 @@
@Override
public void onConnectionChanged(boolean isConnected) {
if (isConnected) {
- updateAssistantAvailability();
+ // We add the OPS callback during construction, so if the service is already connected
+ // then we will try to get the AssistManager dependency which itself has an indirect
+ // dependency on NavBarHelper leading to a cycle. For now, we can defer updating the
+ // assistant availability.
+ mMainExecutor.execute(this::updateAssistantAvailability);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanelController.kt b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanelController.kt
index 93a6eee..b3d848c 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanelController.kt
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanelController.kt
@@ -371,7 +371,6 @@
// Receiving a CANCEL implies that something else intercepted
// the gesture, i.e., the user did not cancel their gesture.
// Therefore, disappear immediately, with minimum fanfare.
- interactionJankMonitor.cancel(CUJ_BACK_PANEL_ARROW)
updateArrowState(GestureState.GONE)
velocityTracker = null
}
@@ -883,16 +882,6 @@
previousState = currentState
currentState = newState
- // First, update the jank tracker
- when (currentState) {
- GestureState.ENTRY -> {
- interactionJankMonitor.cancel(CUJ_BACK_PANEL_ARROW)
- interactionJankMonitor.begin(mView, CUJ_BACK_PANEL_ARROW)
- }
- GestureState.GONE -> interactionJankMonitor.end(CUJ_BACK_PANEL_ARROW)
- else -> {}
- }
-
when (currentState) {
GestureState.CANCELLED -> {
backCallback.cancelBack()
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index a9dd25b..4e89fbf 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -16,6 +16,7 @@
package com.android.systemui.recents;
+import static android.app.Flags.keyguardPrivateNotifications;
import static android.content.Intent.ACTION_PACKAGE_ADDED;
import static android.content.Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST;
import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
@@ -81,6 +82,7 @@
import com.android.internal.util.ScreenshotHelper;
import com.android.internal.util.ScreenshotRequest;
import com.android.systemui.Dumpable;
+import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dump.DumpManager;
@@ -167,13 +169,16 @@
private final Optional<UnfoldTransitionProgressForwarder> mUnfoldTransitionProgressForwarder;
private final UiEventLogger mUiEventLogger;
private final DisplayTracker mDisplayTracker;
-
private Region mActiveNavBarRegion;
+ private final BroadcastDispatcher mBroadcastDispatcher;
+
private IOverviewProxy mOverviewProxy;
private int mConnectionBackoffAttempts;
private boolean mBound;
private boolean mIsEnabled;
+
+ private boolean mIsNonPrimaryUser;
private int mCurrentBoundedUserId = -1;
private boolean mInputFocusTransferStarted;
private float mInputFocusTransferStartY;
@@ -419,6 +424,21 @@
retryConnectionWithBackoff();
};
+ private final BroadcastReceiver mUserEventReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (Objects.equals(intent.getAction(), Intent.ACTION_USER_UNLOCKED)) {
+ if (keyguardPrivateNotifications()) {
+ // Start the overview connection to the launcher service
+ // Connect if user hasn't connected yet
+ if (getProxy() == null) {
+ startConnectionToCurrentUser();
+ }
+ }
+ }
+ }
+ };
+
private final BroadcastReceiver mLauncherStateChangedReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -586,11 +606,13 @@
FeatureFlags featureFlags,
SceneContainerFlags sceneContainerFlags,
DumpManager dumpManager,
- Optional<UnfoldTransitionProgressForwarder> unfoldTransitionProgressForwarder
+ Optional<UnfoldTransitionProgressForwarder> unfoldTransitionProgressForwarder,
+ BroadcastDispatcher broadcastDispatcher
) {
// b/241601880: This component shouldn't be running for a non-primary user
- if (!Process.myUserHandle().equals(UserHandle.SYSTEM)) {
- Log.e(TAG_OPS, "Unexpected initialization for non-primary user", new Throwable());
+ mIsNonPrimaryUser = !Process.myUserHandle().equals(UserHandle.SYSTEM);
+ if (mIsNonPrimaryUser) {
+ Log.wtf(TAG_OPS, "Unexpected initialization for non-primary user", new Throwable());
}
mContext = context;
@@ -615,6 +637,7 @@
mUiEventLogger = uiEventLogger;
mDisplayTracker = displayTracker;
mUnfoldTransitionProgressForwarder = unfoldTransitionProgressForwarder;
+ mBroadcastDispatcher = broadcastDispatcher;
if (!KeyguardWmStateRefactor.isEnabled()) {
mSysuiUnlockAnimationController = sysuiUnlockAnimationController;
@@ -635,6 +658,12 @@
filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
mContext.registerReceiver(mLauncherStateChangedReceiver, filter);
+ if (keyguardPrivateNotifications()) {
+ mBroadcastDispatcher.registerReceiver(mUserEventReceiver,
+ new IntentFilter(Intent.ACTION_USER_UNLOCKED),
+ null /* executor */, UserHandle.ALL);
+ }
+
// Listen for status bar state changes
statusBarWinController.registerCallback(mStatusBarWindowCallback);
mScreenshotHelper = new ScreenshotHelper(context);
@@ -772,6 +801,13 @@
}
private void internalConnectToCurrentUser(String reason) {
+ if (mIsNonPrimaryUser) {
+ // This should not happen, but if any per-user SysUI component has a dependency on OPS,
+ // then this could get triggered
+ Log.w(TAG_OPS, "Skipping connection to overview service due to non-primary user "
+ + "caller");
+ return;
+ }
disconnectFromLauncherService(reason);
// If user has not setup yet or already connected, do not try to connect
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt
index b3d2e09..b9e9fe7 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt
@@ -171,28 +171,6 @@
return repository.setVisible(isVisible)
}
- /** True if there is a transition happening from and to the specified scenes. */
- fun transitioning(from: SceneKey, to: SceneKey): StateFlow<Boolean> {
- fun transitioning(
- state: ObservableTransitionState,
- from: SceneKey,
- to: SceneKey,
- ): Boolean {
- return (state as? ObservableTransitionState.Transition)?.let {
- it.fromScene == from && it.toScene == to
- }
- ?: false
- }
-
- return transitionState
- .map { state -> transitioning(state, from, to) }
- .stateIn(
- scope = applicationScope,
- started = SharingStarted.WhileSubscribed(),
- initialValue = transitioning(transitionState.value, from, to),
- )
- }
-
/**
* Binds the given flow so the system remembers it.
*
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt
index 995059d..246ccb1 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt
@@ -30,6 +30,7 @@
import com.android.systemui.dagger.qualifiers.DisplayId
import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
+import com.android.systemui.model.SceneContainerPlugin
import com.android.systemui.model.SysUiState
import com.android.systemui.model.updateFlags
import com.android.systemui.power.domain.interactor.PowerInteractor
@@ -39,11 +40,6 @@
import com.android.systemui.scene.shared.model.ObservableTransitionState
import com.android.systemui.scene.shared.model.SceneKey
import com.android.systemui.scene.shared.model.SceneModel
-import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BOUNCER_SHOWING
-import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED
-import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE
-import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_QUICK_SETTINGS_EXPANDED
-import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING
import com.android.systemui.statusbar.NotificationShadeWindowController
import com.android.systemui.statusbar.notification.stack.shared.flexiNotifsEnabled
import com.android.systemui.util.asIndenting
@@ -291,12 +287,10 @@
.collect { sceneKey ->
sysUiState.updateFlags(
displayId,
- SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE to (sceneKey != SceneKey.Gone),
- SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED to (sceneKey == SceneKey.Shade),
- SYSUI_STATE_QUICK_SETTINGS_EXPANDED to (sceneKey == SceneKey.QuickSettings),
- SYSUI_STATE_BOUNCER_SHOWING to (sceneKey == SceneKey.Bouncer),
- SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING to
- (sceneKey == SceneKey.Lockscreen),
+ *SceneContainerPlugin.EvaluatorByFlag.map { (flag, evaluator) ->
+ flag to evaluator.invoke(sceneKey)
+ }
+ .toTypedArray(),
)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt b/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt
index 97ec3f9..1c7cc00 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt
@@ -34,7 +34,7 @@
import com.android.systemui.shade.domain.interactor.ShadeInteractor
import com.android.systemui.util.kotlin.collectFlow
import javax.inject.Inject
-import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.Flow
/**
* Controller that's responsible for the glanceable hub container view and its touch handling.
@@ -110,10 +110,8 @@
return communalInteractor.isCommunalEnabled && isComposeAvailable()
}
- /** Returns a {@link StateFlow} that tracks whether communal hub is enabled. */
- fun enabledState(): StateFlow<Boolean> {
- return communalInteractor.communalEnabledState
- }
+ /** Returns a {@link StateFlow} that tracks whether communal hub is available. */
+ fun communalAvailable(): Flow<Boolean> = communalInteractor.isCommunalAvailable
/**
* Creates the container view containing the glanceable hub UI.
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index 530c124..09e4e75 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -66,7 +66,6 @@
import android.os.Handler;
import android.os.Trace;
import android.os.UserManager;
-import android.os.VibrationEffect;
import android.provider.Settings;
import android.util.IndentingPrintWriter;
import android.util.Log;
@@ -256,12 +255,8 @@
private static final boolean DEBUG_LOGCAT = Compile.IS_DEBUG && Log.isLoggable(TAG, Log.DEBUG);
private static final boolean SPEW_LOGCAT = Compile.IS_DEBUG && Log.isLoggable(TAG, Log.VERBOSE);
private static final boolean DEBUG_DRAWABLE = false;
- private static final VibrationEffect ADDITIONAL_TAP_REQUIRED_VIBRATION_EFFECT =
- VibrationEffect.get(VibrationEffect.EFFECT_STRENGTH_MEDIUM, false);
/** The parallax amount of the quick settings translation when dragging down the panel. */
public static final float QS_PARALLAX_AMOUNT = 0.175f;
- /** The delay to reset the hint text when the hint animation is finished running. */
- private static final int HINT_RESET_DELAY_MS = 1200;
private static final long ANIMATION_DELAY_ICON_FADE_IN =
ActivityLaunchAnimator.TIMINGS.getTotalDuration()
- CollapsedStatusBarFragment.FADE_IN_DURATION
@@ -621,7 +616,7 @@
private int mDreamingToLockscreenTransitionTranslationY;
private int mLockscreenToDreamingTransitionTranslationY;
private int mGoneToDreamingTransitionTranslationY;
- private SplitShadeStateController mSplitShadeStateController;
+ private final SplitShadeStateController mSplitShadeStateController;
private final Runnable mFlingCollapseRunnable = () -> fling(0, false /* expand */,
mNextCollapseSpeedUpFactor, false /* expandBecauseOfFalsing */);
private final Runnable mAnimateKeyguardBottomAreaInvisibleEndRunnable =
@@ -636,9 +631,6 @@
}
};
- private final Consumer<Boolean> mMultiShadeExpansionConsumer =
- (Boolean expanded) -> mIsAnyMultiShadeExpanded = expanded;
-
private final Consumer<TransitionStep> mDreamingToLockscreenTransition =
(TransitionStep step) -> {
mIsOcclusionTransitionRunning =
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
index 5ecc54b..19a5840 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
@@ -607,7 +607,7 @@
public void setupCommunalHubLayout() {
collectFlow(
mView,
- mGlanceableHubContainerController.enabledState(),
+ mGlanceableHubContainerController.communalAvailable(),
isEnabled -> {
if (isEnabled) {
View communalPlaceholder = mView.findViewById(R.id.communal_ui_stub);
diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImpl.kt
index 3fd070c..08f2c40 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImpl.kt
@@ -109,7 +109,7 @@
* Returns a flow that uses scene transition progress to and from a scene that is pulled down
* from the top of the screen to a 0-1 expansion amount float.
*/
- internal fun sceneBasedExpansion(sceneInteractor: SceneInteractor, sceneKey: SceneKey) =
+ fun sceneBasedExpansion(sceneInteractor: SceneInteractor, sceneKey: SceneKey) =
sceneInteractor.transitionState
.flatMapLatest { state ->
when (state) {
@@ -135,7 +135,7 @@
* Returns a flow that uses scene transition data to determine whether the user is interacting
* with a scene that is pulled down from the top of the screen.
*/
- internal fun sceneBasedInteracting(sceneInteractor: SceneInteractor, sceneKey: SceneKey) =
+ fun sceneBasedInteracting(sceneInteractor: SceneInteractor, sceneKey: SceneKey) =
sceneInteractor.transitionState
.map { state ->
when (state) {
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModel.kt b/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModel.kt
index 51276c6..314637e 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModel.kt
@@ -22,12 +22,11 @@
import android.icu.text.DateFormat
import android.icu.text.DisplayContext
import android.os.UserHandle
-import com.android.systemui.res.R
import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.res.R
import com.android.systemui.scene.domain.interactor.SceneInteractor
-import com.android.systemui.scene.shared.model.SceneKey
import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractor
import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.MobileIconsViewModel
import java.util.Date
@@ -38,7 +37,6 @@
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
-import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
@@ -57,16 +55,6 @@
val mobileIconsViewModel: MobileIconsViewModel,
broadcastDispatcher: BroadcastDispatcher,
) {
- /** True if we are transitioning between Shade and QuickSettings scenes, in either direction. */
- val isTransitioning =
- combine(
- sceneInteractor.transitioning(from = SceneKey.Shade, to = SceneKey.QuickSettings),
- sceneInteractor.transitioning(from = SceneKey.QuickSettings, to = SceneKey.Shade)
- ) { shadeToQuickSettings, quickSettingsToShade ->
- shadeToQuickSettings || quickSettingsToShade
- }
- .stateIn(applicationScope, SharingStarted.WhileSubscribed(), false)
-
/** True if there is exactly one mobile connection. */
val isSingleCarrier: StateFlow<Boolean> = mobileIconsInteractor.isSingleCarrier
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
index 24ac70e..2a4753d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
@@ -234,10 +234,12 @@
} else if (profileAvailabilityActions(action)) {
updateCurrentProfilesCache();
} else if (Objects.equals(action, Intent.ACTION_USER_UNLOCKED)) {
- // Start the overview connection to the launcher service
- // Connect if user hasn't connected yet
- if (mOverviewProxyServiceLazy.get().getProxy() == null) {
- mOverviewProxyServiceLazy.get().startConnectionToCurrentUser();
+ if (!keyguardPrivateNotifications()) {
+ // Start the overview connection to the launcher service
+ // Connect if user hasn't connected yet
+ if (mOverviewProxyServiceLazy.get().getProxy() == null) {
+ mOverviewProxyServiceLazy.get().startConnectionToCurrentUser();
+ }
}
} else if (Objects.equals(action, NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION)) {
final IntentSender intentSender = intent.getParcelableExtra(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationSnooze.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationSnooze.java
index 3443da1..99a6f6a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationSnooze.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationSnooze.java
@@ -45,13 +45,15 @@
import android.widget.LinearLayout;
import android.widget.TextView;
+import androidx.annotation.NonNull;
+
import com.android.app.animation.Interpolators;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.systemui.res.R;
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper.SnoozeOption;
+import com.android.systemui.res.R;
import java.util.ArrayList;
import java.util.List;
@@ -77,6 +79,9 @@
private static final LogMaker UNDO_LOG =
new LogMaker(MetricsEvent.NOTIFICATION_UNDO_SNOOZE)
.setType(MetricsEvent.TYPE_ACTION);
+
+ private static final String PARAGRAPH_SEPARATOR = "\u2029";
+
private NotificationGuts mGutsContainer;
private NotificationSwipeActionHelper mSnoozeListener;
private StatusBarNotification mSbn;
@@ -111,8 +116,7 @@
}
@VisibleForTesting
- SnoozeOption getDefaultOption()
- {
+ SnoozeOption getDefaultOption() {
return mDefaultOption;
}
@@ -130,6 +134,8 @@
mSelectedOptionText = (TextView) findViewById(R.id.snooze_option_default);
mUndoButton = (TextView) findViewById(R.id.undo);
mUndoButton.setOnClickListener(this);
+ mUndoButton.setContentDescription(
+ getContext().getString(R.string.snooze_undo_content_description));
mExpandButton = (ImageView) findViewById(R.id.expand_button);
mDivider = findViewById(R.id.divider);
mDivider.setAlpha(0f);
@@ -163,6 +169,46 @@
info.addAction(action);
}
}
+
+ mSnoozeView.setAccessibilityDelegate(new AccessibilityDelegate() {
+ @Override
+ public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
+ super.onInitializeAccessibilityNodeInfo(host, info);
+ // Replace "Double tap to activate" prompt with "Double tap to expand/collapse"
+ AccessibilityAction customClick = new AccessibilityAction(
+ AccessibilityNodeInfo.ACTION_CLICK, getExpandActionString());
+ info.addAction(customClick);
+ }
+ });
+ }
+
+ /**
+ * Update the content description of the snooze view based on the snooze option and whether the
+ * snooze options are expanded or not.
+ * For example, this will be something like "Collapsed\u2029Snooze for 1 hour". The paragraph
+ * separator is added to introduce a break in speech, to match what TalkBack does by default
+ * when you e.g. press on a notification.
+ */
+ private void updateContentDescription() {
+ mSnoozeView.setContentDescription(
+ getExpandStateString() + PARAGRAPH_SEPARATOR + mSelectedOptionText.getText());
+ }
+
+ /** Returns "collapse" if the snooze options are expanded, or "expand" otherwise. */
+ @NonNull
+ private String getExpandActionString() {
+ return mContext.getString(mExpanded
+ ? com.android.internal.R.string.expand_button_content_description_expanded
+ : com.android.internal.R.string.expand_button_content_description_collapsed);
+ }
+
+
+ /** Returns "expanded" if the snooze options are expanded, or "collapsed" otherwise. */
+ @NonNull
+ private String getExpandStateString() {
+ return mContext.getString(
+ (mExpanded ? com.android.internal.R.string.content_description_expanded
+ : com.android.internal.R.string.content_description_collapsed));
}
@Override
@@ -179,6 +225,8 @@
if (so.getAccessibilityAction() != null
&& so.getAccessibilityAction().getId() == action) {
setSelected(so, true);
+ mSnoozeView.sendAccessibilityEvent(
+ AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED);
return true;
}
}
@@ -290,11 +338,10 @@
int drawableId = show ? com.android.internal.R.drawable.ic_collapse_notification
: com.android.internal.R.drawable.ic_expand_notification;
mExpandButton.setImageResource(drawableId);
- mExpandButton.setContentDescription(mContext.getString(show
- ? com.android.internal.R.string.expand_button_content_description_expanded
- : com.android.internal.R.string.expand_button_content_description_collapsed));
+ mExpandButton.setContentDescription(getExpandActionString());
if (mExpanded != show) {
mExpanded = show;
+ updateContentDescription();
animateSnoozeOptions(show);
if (mGutsContainer != null) {
mGutsContainer.onHeightChanged();
@@ -335,8 +382,11 @@
}
private void setSelected(SnoozeOption option, boolean userAction) {
- mSelectedOption = option;
- mSelectedOptionText.setText(option.getConfirmation());
+ if (option != mSelectedOption) {
+ mSelectedOption = option;
+ mSelectedOptionText.setText(option.getConfirmation());
+ updateContentDescription();
+ }
showSnoozeOptions(false);
hideSelectedOption();
if (userAction) {
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 7952511..64fcef5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -28,10 +28,10 @@
import static com.android.systemui.Dependency.TIME_TICK_HANDLER_NAME;
import static com.android.systemui.Flags.lightRevealMigration;
+import static com.android.systemui.Flags.predictiveBackSysui;
import static com.android.systemui.charging.WirelessChargingAnimation.UNKNOWN_BATTERY_LEVEL;
import static com.android.systemui.statusbar.NotificationLockscreenUserManager.PERMISSION_SELF;
import static com.android.systemui.statusbar.StatusBarState.SHADE;
-import static com.android.systemui.Flags.predictiveBackSysui;
import android.annotation.Nullable;
import android.app.ActivityOptions;
@@ -95,7 +95,6 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.colorextraction.ColorExtractor;
-import com.android.internal.jank.InteractionJankMonitor;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.UiEvent;
import com.android.internal.logging.UiEventLogger;
@@ -126,6 +125,7 @@
import com.android.systemui.charging.WirelessChargingAnimation;
import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.colorextraction.SysuiColorExtractor;
+import com.android.systemui.communal.domain.interactor.CommunalInteractor;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dagger.qualifiers.UiBackground;
@@ -202,12 +202,10 @@
import com.android.systemui.statusbar.core.StatusBarInitializer;
import com.android.systemui.statusbar.data.model.StatusBarMode;
import com.android.systemui.statusbar.data.repository.StatusBarModeRepositoryStore;
-import com.android.systemui.statusbar.notification.DynamicPrivacyController;
import com.android.systemui.statusbar.notification.NotificationActivityStarter;
import com.android.systemui.statusbar.notification.NotificationLaunchAnimatorControllerProvider;
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
import com.android.systemui.statusbar.notification.init.NotificationsController;
-import com.android.systemui.statusbar.notification.interruption.VisualInterruptionDecisionProvider;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.notification.shared.NotificationIconContainerRefactor;
@@ -225,7 +223,6 @@
import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.statusbar.policy.UserInfoControllerImpl;
-import com.android.systemui.statusbar.policy.UserSwitcherController;
import com.android.systemui.statusbar.window.StatusBarWindowController;
import com.android.systemui.statusbar.window.StatusBarWindowStateController;
import com.android.systemui.surfaceeffects.ripple.RippleShader.RippleShape;
@@ -249,6 +246,7 @@
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.Executor;
+import java.util.function.Consumer;
import javax.inject.Inject;
import javax.inject.Named;
@@ -278,19 +276,9 @@
private static final String BANNER_ACTION_SETUP =
"com.android.systemui.statusbar.banner_action_setup";
- private static final int MSG_OPEN_SETTINGS_PANEL = 1002;
private static final int MSG_LAUNCH_TRANSITION_TIMEOUT = 1003;
// 1020-1040 reserved for BaseStatusBar
- /**
- * TODO(b/249277686) delete this
- * The delay to reset the hint text when the hint animation is finished running.
- */
- private static final int HINT_RESET_DELAY_MS = 1200;
-
- /** If true, the lockscreen will show a distinct wallpaper */
- public static final boolean ENABLE_LOCKSCREEN_WALLPAPER = true;
-
private static final UiEventLogger sUiEventLogger = new UiEventLoggerImpl();
private final Context mContext;
@@ -300,7 +288,7 @@
private CentralSurfacesCommandQueueCallbacks mCommandQueueCallbacks;
private float mTransitionToFullShadeProgress = 0f;
private final NotificationListContainer mNotifListContainer;
- private boolean mIsShortcutListSearchEnabled;
+ private final boolean mIsShortcutListSearchEnabled;
private final KeyguardStateController.Callback mKeyguardStateControllerCallback =
new KeyguardStateController.Callback() {
@@ -459,7 +447,6 @@
private final NotificationGutsManager mGutsManager;
private final ShadeExpansionStateManager mShadeExpansionStateManager;
private final KeyguardViewMediator mKeyguardViewMediator;
- private final VisualInterruptionDecisionProvider mVisualInterruptionDecisionProvider;
private final BrightnessSliderController.Factory mBrightnessSliderFactory;
private final FeatureFlags mFeatureFlags;
private final FragmentService mFragmentService;
@@ -555,7 +542,6 @@
private int mLastLoggedStateFingerprint;
private boolean mIsLaunchingActivityOverLockscreen;
- private final UserSwitcherController mUserSwitcherController;
private final LifecycleRegistry mLifecycle = new LifecycleRegistry(this);
protected final BatteryController mBatteryController;
private UiModeManager mUiModeManager;
@@ -567,6 +553,25 @@
private final WakefulnessLifecycle mWakefulnessLifecycle;
protected final PowerInteractor mPowerInteractor;
+ private final CommunalInteractor mCommunalInteractor;
+
+ /**
+ * True if the device is showing the glanceable hub. See
+ * {@link CommunalInteractor#isIdleOnCommunal()} for more details.
+ */
+ private boolean mIsIdleOnCommunal = false;
+ private final Consumer<Boolean> mIdleOnCommunalConsumer = (Boolean idleOnCommunal) -> {
+ if (idleOnCommunal == mIsIdleOnCommunal) {
+ // Ignore initial value coming through the flow.
+ return;
+ }
+
+ mIsIdleOnCommunal = idleOnCommunal;
+ // Trigger an update for the scrim state when we enter or exit glanceable hub, so that we
+ // can transition to/from ScrimState.GLANCEABLE_HUB if needed.
+ updateScrimController();
+ };
+
private boolean mNoAnimationOnNextBarModeChange;
private final SysuiStatusBarStateController mStatusBarStateController;
@@ -586,8 +591,6 @@
private final ColorExtractor.OnColorsChangedListener mOnColorsChangedListener =
(extractor, which) -> updateTheme();
- private final InteractionJankMonitor mJankMonitor;
-
private final SceneContainerFlags mSceneContainerFlags;
/**
@@ -615,12 +618,10 @@
KeyguardBypassController keyguardBypassController,
KeyguardStateController keyguardStateController,
HeadsUpManager headsUpManager,
- DynamicPrivacyController dynamicPrivacyController,
FalsingManager falsingManager,
FalsingCollector falsingCollector,
BroadcastDispatcher broadcastDispatcher,
NotificationGutsManager notificationGutsManager,
- VisualInterruptionDecisionProvider visualInterruptionDecisionProvider,
ShadeExpansionStateManager shadeExpansionStateManager,
KeyguardViewMediator keyguardViewMediator,
DisplayMetrics displayMetrics,
@@ -633,12 +634,12 @@
NotificationLockscreenUserManager lockScreenUserManager,
NotificationRemoteInputManager remoteInputManager,
QuickSettingsController quickSettingsController,
- UserSwitcherController userSwitcherController,
BatteryController batteryController,
SysuiColorExtractor colorExtractor,
ScreenLifecycle screenLifecycle,
WakefulnessLifecycle wakefulnessLifecycle,
PowerInteractor powerInteractor,
+ CommunalInteractor communalInteractor,
SysuiStatusBarStateController statusBarStateController,
Optional<Bubbles> bubblesOptional,
Lazy<NoteTaskController> noteTaskControllerLazy,
@@ -693,7 +694,6 @@
WallpaperManager wallpaperManager,
Optional<StartingSurface> startingSurfaceOptional,
ActivityLaunchAnimator activityLaunchAnimator,
- InteractionJankMonitor jankMonitor,
DeviceStateManager deviceStateManager,
WiredChargingRippleController wiredChargingRippleController,
IDreamManager dreamManager,
@@ -727,7 +727,6 @@
mFalsingManager = falsingManager;
mBroadcastDispatcher = broadcastDispatcher;
mGutsManager = notificationGutsManager;
- mVisualInterruptionDecisionProvider = visualInterruptionDecisionProvider;
mShadeExpansionStateManager = shadeExpansionStateManager;
mKeyguardViewMediator = keyguardViewMediator;
mDisplayMetrics = displayMetrics;
@@ -740,12 +739,12 @@
mLockscreenUserManager = lockScreenUserManager;
mRemoteInputManager = remoteInputManager;
mQsController = quickSettingsController;
- mUserSwitcherController = userSwitcherController;
mBatteryController = batteryController;
mColorExtractor = colorExtractor;
mScreenLifecycle = screenLifecycle;
mWakefulnessLifecycle = wakefulnessLifecycle;
mPowerInteractor = powerInteractor;
+ mCommunalInteractor = communalInteractor;
mStatusBarStateController = statusBarStateController;
mBubblesOptional = bubblesOptional;
mNoteTaskControllerLazy = noteTaskControllerLazy;
@@ -795,7 +794,6 @@
mMainExecutor = delayableExecutor;
mMessageRouter = messageRouter;
mWallpaperManager = wallpaperManager;
- mJankMonitor = jankMonitor;
mCameraLauncherLazy = cameraLauncherLazy;
mAlternateBouncerInteractor = alternateBouncerInteractor;
mUserTracker = userTracker;
@@ -1076,6 +1074,10 @@
//TODO(b/264502026) move the rest of the listeners here.
mDeviceStateManager.registerCallback(mMainExecutor,
new FoldStateListener(mContext, this::onFoldedStateChanged));
+
+ mJavaAdapter.alwaysCollectFlow(
+ mCommunalInteractor.isIdleOnCommunal(),
+ mIdleOnCommunalConsumer);
}
/**
@@ -2820,6 +2822,8 @@
// This will cancel the keyguardFadingAway animation if it is running. We need to do
// this as otherwise it can remain pending and leave keyguard in a weird state.
mUnlockScrimCallback.onCancelled();
+ } else if (mIsIdleOnCommunal) {
+ mScrimController.transitionTo(ScrimState.GLANCEABLE_HUB);
} else if (mKeyguardStateController.isShowing()
&& !mKeyguardStateController.isOccluded()
&& !unlocking) {
@@ -3087,7 +3091,7 @@
}
};
- private StatusBarStateController.StateListener mStateListener =
+ private final StatusBarStateController.StateListener mStateListener =
new StatusBarStateController.StateListener() {
@Override
public void onStatePreChange(int oldState, int newState) {
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 aabe4a0..6f78604 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -17,7 +17,9 @@
package com.android.systemui.statusbar.phone;
import static com.android.systemui.keyguard.shared.model.KeyguardState.ALTERNATE_BOUNCER;
+import static com.android.systemui.keyguard.shared.model.KeyguardState.GLANCEABLE_HUB;
import static com.android.systemui.keyguard.shared.model.KeyguardState.GONE;
+import static com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN;
import static com.android.systemui.keyguard.shared.model.KeyguardState.PRIMARY_BOUNCER;
import static com.android.systemui.util.kotlin.JavaAdapterKt.collectFlow;
@@ -62,6 +64,7 @@
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
+import com.android.systemui.keyguard.shared.model.KeyguardState;
import com.android.systemui.keyguard.shared.model.ScrimAlpha;
import com.android.systemui.keyguard.shared.model.TransitionState;
import com.android.systemui.keyguard.shared.model.TransitionStep;
@@ -292,6 +295,30 @@
mScrimBehind.setViewAlpha(mBehindAlpha);
};
+ /**
+ * Consumer that fades the behind scrim in and out during the transition between the lock screen
+ * and the glanceable hub.
+ *
+ * While the lock screen is showing, the behind scrim is used to slightly darken the lock screen
+ * wallpaper underneath. Since the glanceable hub is under all of the scrims, we want to fade
+ * out the scrim so that the glanceable hub isn't darkened when it opens.
+ *
+ * {@link #applyState()} handles the scrim alphas once on the glanceable hub, this is only
+ * responsible for setting the behind alpha during the transition.
+ */
+ private final Consumer<TransitionStep> mGlanceableHubConsumer = (TransitionStep step) -> {
+ final float baseAlpha = ScrimState.KEYGUARD.getBehindAlpha();
+ final float transitionProgress = step.getValue();
+ if (step.getTo() == KeyguardState.LOCKSCREEN) {
+ // Transitioning back to lock screen, fade in behind scrim again.
+ mBehindAlpha = baseAlpha * transitionProgress;
+ } else if (step.getTo() == GLANCEABLE_HUB) {
+ // Transitioning to glanceable hub, fade out behind scrim.
+ mBehindAlpha = baseAlpha * (1 - transitionProgress);
+ }
+ mScrimBehind.setViewAlpha(mBehindAlpha);
+ };
+
Consumer<TransitionStep> mBouncerToGoneTransition;
@Inject
@@ -444,6 +471,14 @@
mBouncerToGoneTransition, mMainDispatcher);
collectFlow(behindScrim, mAlternateBouncerToGoneTransitionViewModel.getScrimAlpha(),
mScrimAlphaConsumer, mMainDispatcher);
+
+ // LOCKSCREEN<->GLANCEABLE_HUB
+ collectFlow(behindScrim,
+ mKeyguardTransitionInteractor.transition(LOCKSCREEN, GLANCEABLE_HUB),
+ mGlanceableHubConsumer, mMainDispatcher);
+ collectFlow(behindScrim,
+ mKeyguardTransitionInteractor.transition(GLANCEABLE_HUB, LOCKSCREEN),
+ mGlanceableHubConsumer, mMainDispatcher);
}
// TODO(b/270984686) recompute scrim height accurately, based on shade contents.
@@ -763,10 +798,15 @@
// see: b/186644628
mNotificationsScrim.setDrawableBounds(left - 1, top, right + 1, bottom);
mScrimBehind.setBottomEdgePosition((int) top);
+ } else {
+ mNotificationsScrim.setDrawableBounds(left, top, right, bottom);
+ }
+
+ // Only clip if the notif scrim is visible
+ if (mNotificationsAlpha > 0f) {
mKeyguardInteractor.setTopClippingBounds((int) top);
} else {
mKeyguardInteractor.setTopClippingBounds(null);
- mNotificationsScrim.setDrawableBounds(left, top, right, bottom);
}
}
@@ -810,9 +850,9 @@
return;
}
mBouncerHiddenFraction = bouncerHiddenAmount;
- if (mState == ScrimState.DREAMING) {
- // Only the dreaming state requires this for the scrim calculation, so we should
- // only trigger an update if dreaming.
+ if (mState == ScrimState.DREAMING || mState == ScrimState.GLANCEABLE_HUB) {
+ // The dreaming and glanceable hub states requires this for the scrim calculation, so we
+ // should only trigger an update in those states.
applyAndDispatchState();
}
}
@@ -934,7 +974,7 @@
} else if (mState == ScrimState.AUTH_SCRIMMED_SHADE) {
mNotificationsAlpha = (float) Math.pow(getInterpolatedFraction(), 0.8f);
} else if (mState == ScrimState.KEYGUARD || mState == ScrimState.SHADE_LOCKED
- || mState == ScrimState.PULSING) {
+ || mState == ScrimState.PULSING || mState == ScrimState.GLANCEABLE_HUB) {
Pair<Integer, Float> result = calculateBackStateForState(mState);
int behindTint = result.first;
float behindAlpha = result.second;
@@ -945,6 +985,11 @@
mTransitionToFullShadeProgress);
behindTint = ColorUtils.blendARGB(behindTint, shadeResult.first,
mTransitionToFullShadeProgress);
+ } else if (mState == ScrimState.GLANCEABLE_HUB && mTransitionToFullShadeProgress == 0.0f
+ && mBouncerHiddenFraction == KeyguardBouncerConstants.EXPANSION_HIDDEN) {
+ // Behind scrim should not be visible when idle on the glanceable hub and neither
+ // bouncer nor shade are showing.
+ behindAlpha = 0f;
}
mInFrontAlpha = mState.getFrontAlpha();
if (mClipsQsScrim) {
@@ -960,6 +1005,13 @@
} else if (mState == ScrimState.SHADE_LOCKED) {
// going from KEYGUARD to SHADE_LOCKED state
mNotificationsAlpha = getInterpolatedFraction();
+ } else if (mState == ScrimState.GLANCEABLE_HUB
+ && mTransitionToFullShadeProgress == 0.0f) {
+ // Notification scrim should not be visible on the glanceable hub unless the
+ // shade is showing or transitioning in. Otherwise the notification scrim will
+ // be visible as the bouncer transitions in or after the notification shade
+ // closes.
+ mNotificationsAlpha = 0;
} else {
mNotificationsAlpha = Math.max(1.0f - getInterpolatedFraction(), mQsExpansion);
}
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 e3b65ab..f2a649b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
@@ -20,6 +20,7 @@
import android.os.Trace;
import com.android.systemui.dock.DockManager;
+import com.android.systemui.res.R;
import com.android.systemui.scrim.ScrimView;
import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
@@ -39,8 +40,8 @@
OFF {
@Override
public void prepare(ScrimState previousState) {
- mFrontTint = Color.BLACK;
- mBehindTint = Color.BLACK;
+ mFrontTint = mBackgroundColor;
+ mBehindTint = mBackgroundColor;
mFrontAlpha = 1f;
mBehindAlpha = 1f;
@@ -74,15 +75,15 @@
} else {
mAnimationDuration = ScrimController.ANIMATION_DURATION;
}
- mFrontTint = Color.BLACK;
- mBehindTint = Color.BLACK;
- mNotifTint = mClipQsScrim ? Color.BLACK : Color.TRANSPARENT;
+ mFrontTint = mBackgroundColor;
+ mBehindTint = mBackgroundColor;
+ mNotifTint = mClipQsScrim ? mBackgroundColor : Color.TRANSPARENT;
mFrontAlpha = 0;
mBehindAlpha = mClipQsScrim ? 1 : mScrimBehindAlphaKeyguard;
mNotifAlpha = mClipQsScrim ? mScrimBehindAlphaKeyguard : 0;
if (mClipQsScrim) {
- updateScrimColor(mScrimBehind, 1f /* alpha */, Color.BLACK);
+ updateScrimColor(mScrimBehind, 1f /* alpha */, mBackgroundColor);
}
}
},
@@ -93,10 +94,10 @@
// notif scrim alpha values are determined by ScrimController#applyState
// based on the shade expansion
- mFrontTint = Color.BLACK;
+ mFrontTint = mBackgroundColor;
mFrontAlpha = .66f;
- mBehindTint = Color.BLACK;
+ mBehindTint = mBackgroundColor;
mBehindAlpha = 1f;
}
},
@@ -110,7 +111,7 @@
mBehindTint = previousState.mBehindTint;
mBehindAlpha = previousState.mBehindAlpha;
- mFrontTint = Color.BLACK;
+ mFrontTint = mBackgroundColor;
mFrontAlpha = .66f;
}
},
@@ -122,7 +123,7 @@
@Override
public void prepare(ScrimState previousState) {
mBehindAlpha = mClipQsScrim ? 1 : mDefaultScrimAlpha;
- mBehindTint = mClipQsScrim ? Color.BLACK : mSurfaceColor;
+ mBehindTint = mClipQsScrim ? mBackgroundColor : mSurfaceColor;
mNotifAlpha = mClipQsScrim ? mDefaultScrimAlpha : 0;
mNotifTint = Color.TRANSPARENT;
mFrontAlpha = 0f;
@@ -154,10 +155,10 @@
mBehindAlpha = mClipQsScrim ? 1 : mDefaultScrimAlpha;
mNotifAlpha = 1f;
mFrontAlpha = 0f;
- mBehindTint = mClipQsScrim ? Color.TRANSPARENT : Color.BLACK;
+ mBehindTint = mClipQsScrim ? Color.TRANSPARENT : mBackgroundColor;
if (mClipQsScrim) {
- updateScrimColor(mScrimBehind, 1f /* alpha */, Color.BLACK);
+ updateScrimColor(mScrimBehind, 1f /* alpha */, mBackgroundColor);
}
}
},
@@ -184,11 +185,11 @@
final boolean isDocked = mDockManager.isDocked();
mBlankScreen = mDisplayRequiresBlanking;
- mFrontTint = Color.BLACK;
+ mFrontTint = mBackgroundColor;
mFrontAlpha = (alwaysOnEnabled || isDocked || quickPickupEnabled)
? mAodFrontScrimAlpha : 1f;
- mBehindTint = Color.BLACK;
+ mBehindTint = mBackgroundColor;
mBehindAlpha = ScrimController.TRANSPARENT;
mAnimationDuration = ScrimController.ANIMATION_DURATION_LONG;
@@ -222,8 +223,8 @@
@Override
public void prepare(ScrimState previousState) {
mFrontAlpha = mAodFrontScrimAlpha;
- mBehindTint = Color.BLACK;
- mFrontTint = Color.BLACK;
+ mBehindTint = mBackgroundColor;
+ mFrontTint = mBackgroundColor;
mBlankScreen = mDisplayRequiresBlanking;
mAnimationDuration = mWakeLockScreenSensorActive
? ScrimController.ANIMATION_DURATION_LONG : ScrimController.ANIMATION_DURATION;
@@ -231,7 +232,7 @@
@Override
public float getMaxLightRevealScrimAlpha() {
return mWakeLockScreenSensorActive ? ScrimController.WAKE_SENSOR_SCRIM_ALPHA
- : AOD.getMaxLightRevealScrimAlpha();
+ : AOD.getMaxLightRevealScrimAlpha();
}
},
@@ -245,7 +246,6 @@
mBehindAlpha = mClipQsScrim ? 1 : 0;
mNotifAlpha = 0;
mFrontAlpha = 0;
-
mAnimationDuration = mKeyguardFadingAway
? mKeyguardFadingAwayDuration
: CentralSurfaces.FADE_KEYGUARD_DURATION;
@@ -259,22 +259,22 @@
&& !fromAod;
mFrontTint = Color.TRANSPARENT;
- mBehindTint = Color.BLACK;
+ mBehindTint = mBackgroundColor;
mBlankScreen = false;
if (mDisplayRequiresBlanking && previousState == ScrimState.AOD) {
// Set all scrims black, before they fade transparent.
- updateScrimColor(mScrimInFront, 1f /* alpha */, Color.BLACK /* tint */);
- updateScrimColor(mScrimBehind, 1f /* alpha */, Color.BLACK /* tint */);
+ updateScrimColor(mScrimInFront, 1f /* alpha */, mBackgroundColor /* tint */);
+ updateScrimColor(mScrimBehind, 1f /* alpha */, mBackgroundColor /* tint */);
// Scrims should still be black at the end of the transition.
- mFrontTint = Color.BLACK;
- mBehindTint = Color.BLACK;
+ mFrontTint = mBackgroundColor;
+ mBehindTint = mBackgroundColor;
mBlankScreen = true;
}
if (mClipQsScrim) {
- updateScrimColor(mScrimBehind, 1f /* alpha */, Color.BLACK);
+ updateScrimColor(mScrimBehind, 1f /* alpha */, mBackgroundColor);
}
}
},
@@ -283,8 +283,8 @@
@Override
public void prepare(ScrimState previousState) {
mFrontTint = Color.TRANSPARENT;
- mBehindTint = Color.BLACK;
- mNotifTint = mClipQsScrim ? Color.BLACK : Color.TRANSPARENT;
+ mBehindTint = mBackgroundColor;
+ mNotifTint = mClipQsScrim ? mBackgroundColor : Color.TRANSPARENT;
mFrontAlpha = 0;
mBehindAlpha = mClipQsScrim ? 1 : 0;
@@ -293,9 +293,24 @@
mBlankScreen = false;
if (mClipQsScrim) {
- updateScrimColor(mScrimBehind, 1f /* alpha */, Color.BLACK);
+ updateScrimColor(mScrimBehind, 1f /* alpha */, mBackgroundColor);
}
}
+ },
+
+ /**
+ * Device is locked or on dream and user has swiped from the right edge to enter the glanceable
+ * hub UI. From this state, the user can swipe from the left edge to go back to the lock screen
+ * or dream, as well as swipe down for the notifications and up for the bouncer.
+ */
+ GLANCEABLE_HUB {
+ @Override
+ public void prepare(ScrimState previousState) {
+ // No scrims should be visible by default in this state.
+ mBehindAlpha = 0;
+ mNotifAlpha = 0;
+ mFrontAlpha = 0;
+ }
};
boolean mBlankScreen = false;
@@ -327,9 +342,11 @@
boolean mKeyguardFadingAway;
long mKeyguardFadingAwayDuration;
boolean mClipQsScrim;
+ int mBackgroundColor;
public void init(ScrimView scrimInFront, ScrimView scrimBehind, DozeParameters dozeParameters,
DockManager dockManager) {
+ mBackgroundColor = scrimBehind.getContext().getColor(R.color.shade_scrim_background_dark);
mScrimInFront = scrimInFront;
mScrimBehind = scrimBehind;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/data/prod/DeviceBasedSatelliteRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/data/prod/DeviceBasedSatelliteRepositoryImpl.kt
index 0e67756..f73d089 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/data/prod/DeviceBasedSatelliteRepositoryImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/data/prod/DeviceBasedSatelliteRepositoryImpl.kt
@@ -153,7 +153,14 @@
if (satelliteManager != null) {
// First, check that satellite is supported on this device
scope.launch {
- ensureMinUptime(systemClock, MIN_UPTIME)
+ val waitTime = ensureMinUptime(systemClock, MIN_UPTIME)
+ if (waitTime > 0) {
+ logBuffer.i({ long1 = waitTime }) {
+ "Waiting $long1 ms before checking for satellite support"
+ }
+ delay(waitTime)
+ }
+
satelliteSupport.value = satelliteManager.checkSatelliteSupported()
logBuffer.i(
@@ -176,7 +183,7 @@
*/
while (true) {
logBuffer.i {
- "requestIsSatelliteCommunicationAllowedForCurrentLocation"
+ "requestIsCommunicationAllowedForCurrentLocation"
}
checkIsSatelliteAllowed()
delay(POLLING_INTERVAL_MS)
@@ -209,14 +216,13 @@
var registered = false
try {
- val res =
- sm.registerForSatelliteModemStateChanged(bgDispatcher.asExecutor(), cb)
+ val res = sm.registerForModemStateChanged(bgDispatcher.asExecutor(), cb)
registered = res == SATELLITE_RESULT_SUCCESS
} catch (e: Exception) {
logBuffer.e("error registering for modem state", e)
}
- awaitClose { if (registered) sm.unregisterForSatelliteModemStateChanged(cb) }
+ awaitClose { if (registered) sm.unregisterForModemStateChanged(cb) }
}
.flowOn(bgDispatcher)
@@ -248,7 +254,7 @@
/** Fire off a request to check for satellite availability. Always runs on the bg context */
private suspend fun checkIsSatelliteAllowed() =
withContext(bgDispatcher) {
- satelliteManager?.requestIsSatelliteCommunicationAllowedForCurrentLocation(
+ satelliteManager?.requestIsCommunicationAllowedForCurrentLocation(
bgDispatcher.asExecutor(),
object : OutcomeReceiver<Boolean, SatelliteManager.SatelliteException> {
override fun onError(e: SatelliteManager.SatelliteException) {
@@ -260,7 +266,7 @@
}
override fun onResult(allowed: Boolean) {
- logBuffer.i { allowed.toString() }
+ logBuffer.i { "isSatelliteAllowedForCurrentLocation: $allowed" }
isSatelliteAllowedForCurrentLocation.value = allowed
}
}
@@ -294,7 +300,7 @@
}
try {
- requestIsSatelliteSupported(bgDispatcher.asExecutor(), cb)
+ requestIsSupported(bgDispatcher.asExecutor(), cb)
} catch (error: Exception) {
logBuffer.e(
"Exception when checking for satellite support. " +
@@ -309,19 +315,14 @@
// TTL for satellite polling is one hour
const val POLLING_INTERVAL_MS: Long = 1000 * 60 * 60
- // Let the system boot up and stabilize before we check for system support
- const val MIN_UPTIME: Long = 1000 * 60
+ // Let the system boot up (5s) and stabilize before we check for system support
+ const val MIN_UPTIME: Long = 1000 * 5
private const val TAG = "DeviceBasedSatelliteRepo"
- /** If our process hasn't been up for at least MIN_UPTIME, delay until we reach that time */
- private suspend fun ensureMinUptime(clock: SystemClock, uptime: Long) {
- val timeTilMinUptime =
- uptime - (clock.uptimeMillis() - android.os.Process.getStartUptimeMillis())
- if (timeTilMinUptime > 0) {
- delay(timeTilMinUptime)
- }
- }
+ /** Calculates how long we have to wait to reach MIN_UPTIME */
+ private fun ensureMinUptime(clock: SystemClock, uptime: Long): Long =
+ uptime - (clock.uptimeMillis() - android.os.Process.getStartUptimeMillis())
/** A couple of convenience logging methods rather than a whole class */
private fun LogBuffer.i(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractor.kt
index 8779577..6e1114c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractor.kt
@@ -79,7 +79,7 @@
} else {
flowOf(false)
}
- .stateIn(scope, SharingStarted.WhileSubscribed(), false)
+ .stateIn(scope, SharingStarted.WhileSubscribed(), true)
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/unfold/SysUIUnfoldModule.kt b/packages/SystemUI/src/com/android/systemui/unfold/SysUIUnfoldModule.kt
index 10fc83c..0016d95 100644
--- a/packages/SystemUI/src/com/android/systemui/unfold/SysUIUnfoldModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/unfold/SysUIUnfoldModule.kt
@@ -26,7 +26,6 @@
import com.android.systemui.unfold.util.UnfoldKeyguardVisibilityManager
import com.android.systemui.util.kotlin.getOrNull
import dagger.BindsInstance
-import dagger.Lazy
import dagger.Module
import dagger.Provides
import dagger.Subcomponent
@@ -57,7 +56,6 @@
rotationProvider: Optional<NaturalRotationUnfoldProgressProvider>,
@Named(UNFOLD_STATUS_BAR) scopedProvider: Optional<ScopedUnfoldTransitionProgressProvider>,
@UnfoldBg bgProvider: Optional<UnfoldTransitionProgressProvider>,
- unfoldLatencyTracker: Lazy<UnfoldLatencyTracker>,
factory: SysUIUnfoldComponent.Factory
): Optional<SysUIUnfoldComponent> {
val p1 = provider.getOrNull()
@@ -67,7 +65,7 @@
return if (p1 == null || p2 == null || p3 == null || p4 == null) {
Optional.empty()
} else {
- Optional.of(factory.create(p1, p2, p3, p4, unfoldLatencyTracker.get()))
+ Optional.of(factory.create(p1, p2, p3, p4))
}
}
}
@@ -82,8 +80,7 @@
@BindsInstance p1: UnfoldTransitionProgressProvider,
@BindsInstance p2: NaturalRotationUnfoldProgressProvider,
@BindsInstance p3: ScopedUnfoldTransitionProgressProvider,
- @BindsInstance @UnfoldBg p4: UnfoldTransitionProgressProvider,
- @BindsInstance p5: UnfoldLatencyTracker,
+ @BindsInstance @UnfoldBg p4: UnfoldTransitionProgressProvider
): SysUIUnfoldComponent
}
diff --git a/packages/SystemUI/src/com/android/systemui/unfold/UnfoldLatencyTracker.kt b/packages/SystemUI/src/com/android/systemui/unfold/UnfoldLatencyTracker.kt
index 8c66c2f..33fa9b8 100644
--- a/packages/SystemUI/src/com/android/systemui/unfold/UnfoldLatencyTracker.kt
+++ b/packages/SystemUI/src/com/android/systemui/unfold/UnfoldLatencyTracker.kt
@@ -22,7 +22,6 @@
import android.os.Trace
import android.util.Log
import com.android.internal.util.LatencyTracker
-import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.UiBackground
import com.android.systemui.keyguard.ScreenLifecycle
import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener
@@ -42,7 +41,7 @@
* For now, the focus is on the time the inner display is visible, but in the future, it is easily
* possible to monitor the time to go from the inner screen to the outer.
*/
-@SysUISingleton
+@SysUIUnfoldScope
class UnfoldLatencyTracker
@Inject
constructor(
diff --git a/packages/SystemUI/src/com/android/systemui/unfold/UnfoldTransitionModule.kt b/packages/SystemUI/src/com/android/systemui/unfold/UnfoldTransitionModule.kt
index 8bef53c..9bd0e32 100644
--- a/packages/SystemUI/src/com/android/systemui/unfold/UnfoldTransitionModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/unfold/UnfoldTransitionModule.kt
@@ -177,17 +177,20 @@
@Module
interface Bindings {
- @Binds
- @IntoMap
- @ClassKey(UnfoldTraceLogger::class)
- fun bindUnfoldTraceLogger(impl: UnfoldTraceLogger): CoreStartable
-
@Binds fun bindRepository(impl: UnfoldTransitionRepositoryImpl): UnfoldTransitionRepository
@Binds fun bindInteractor(impl: UnfoldTransitionInteractorImpl): UnfoldTransitionInteractor
@Binds fun bindFoldStateRepository(impl: FoldStateRepositoryImpl): FoldStateRepository
}
+
+ @Module
+ interface Startables {
+ @Binds
+ @IntoMap
+ @ClassKey(UnfoldTraceLogger::class)
+ fun bindUnfoldTraceLogger(impl: UnfoldTraceLogger): CoreStartable
+ }
}
const val UNFOLD_STATUS_BAR = "unfold_status_bar"
diff --git a/packages/SystemUI/src/com/android/systemui/util/kotlin/CoroutinesModule.kt b/packages/SystemUI/src/com/android/systemui/util/kotlin/CoroutinesModule.kt
deleted file mode 100644
index cf6b0d9..0000000
--- a/packages/SystemUI/src/com/android/systemui/util/kotlin/CoroutinesModule.kt
+++ /dev/null
@@ -1,85 +0,0 @@
-package com.android.systemui.util.kotlin
-
-import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.dagger.qualifiers.Application
-import com.android.systemui.dagger.qualifiers.Background
-import com.android.systemui.dagger.qualifiers.Main
-import com.android.systemui.dagger.qualifiers.Tracing
-import com.android.app.tracing.coroutines.createCoroutineTracingContext
-import dagger.Module
-import dagger.Provides
-import kotlinx.coroutines.CoroutineDispatcher
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.plus
-import kotlin.coroutines.CoroutineContext
-
-/** Providers for various coroutines-related constructs. */
-@Module
-class CoroutinesModule {
- @Provides
- @SysUISingleton
- @Application
- fun applicationScope(
- @Main dispatcherContext: CoroutineContext,
- ): CoroutineScope = CoroutineScope(dispatcherContext)
-
- @Provides
- @SysUISingleton
- @Background
- fun bgApplicationScope(
- @Application applicationScope: CoroutineScope,
- @Background coroutineContext: CoroutineContext,
- ): CoroutineScope = applicationScope.plus(coroutineContext)
-
- @Provides
- @SysUISingleton
- @Main
- @Deprecated(
- "Use @Main CoroutineContext instead",
- ReplaceWith("mainCoroutineContext()", "kotlin.coroutines.CoroutineContext")
- )
- fun mainDispatcher(): CoroutineDispatcher = Dispatchers.Main.immediate
-
- @Provides
- @SysUISingleton
- @Main
- fun mainCoroutineContext(@Tracing tracingCoroutineContext: CoroutineContext): CoroutineContext {
- return Dispatchers.Main.immediate + tracingCoroutineContext
- }
-
- /**
- * Provide a [CoroutineDispatcher] backed by a thread pool containing at most X threads, where
- * X is the number of CPU cores available.
- *
- * Because there are multiple threads at play, there is no serialization order guarantee. You
- * should use a [kotlinx.coroutines.channels.Channel] for serialization if necessary.
- *
- * @see Dispatchers.Default
- */
- @Provides
- @SysUISingleton
- @Background
- @Deprecated(
- "Use @Background CoroutineContext instead",
- ReplaceWith("bgCoroutineContext()", "kotlin.coroutines.CoroutineContext")
- )
- fun bgDispatcher(): CoroutineDispatcher = Dispatchers.IO
-
-
- @Provides
- @Background
- @SysUISingleton
- fun bgCoroutineContext(@Tracing tracingCoroutineContext: CoroutineContext): CoroutineContext {
- return Dispatchers.IO + tracingCoroutineContext
- }
-
- @OptIn(ExperimentalCoroutinesApi::class)
- @Provides
- @Tracing
- @SysUISingleton
- fun tracingCoroutineContext(): CoroutineContext {
- return createCoroutineTracingContext()
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/util/kotlin/GlobalCoroutinesModule.kt b/packages/SystemUI/src/com/android/systemui/util/kotlin/GlobalCoroutinesModule.kt
new file mode 100644
index 0000000..8ecf250
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/kotlin/GlobalCoroutinesModule.kt
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.util.kotlin
+
+import com.android.app.tracing.coroutines.createCoroutineTracingContext
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.dagger.qualifiers.Tracing
+import dagger.Module
+import dagger.Provides
+import javax.inject.Singleton
+import kotlin.coroutines.CoroutineContext
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+
+/** Providers for various application-wide coroutines-related constructs. */
+@Module
+class GlobalCoroutinesModule {
+ @Provides
+ @Singleton
+ @Application
+ fun applicationScope(
+ @Main dispatcherContext: CoroutineContext,
+ ): CoroutineScope = CoroutineScope(dispatcherContext)
+
+ @Provides
+ @Singleton
+ @Main
+ @Deprecated(
+ "Use @Main CoroutineContext instead",
+ ReplaceWith("mainCoroutineContext()", "kotlin.coroutines.CoroutineContext")
+ )
+ fun mainDispatcher(): CoroutineDispatcher = Dispatchers.Main.immediate
+
+ @Provides
+ @Singleton
+ @Main
+ fun mainCoroutineContext(@Tracing tracingCoroutineContext: CoroutineContext): CoroutineContext {
+ return Dispatchers.Main.immediate + tracingCoroutineContext
+ }
+
+ @OptIn(ExperimentalCoroutinesApi::class)
+ @Provides
+ @Tracing
+ @Singleton
+ fun tracingCoroutineContext(): CoroutineContext {
+ return createCoroutineTracingContext()
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/util/kotlin/SysUICoroutinesModule.kt b/packages/SystemUI/src/com/android/systemui/util/kotlin/SysUICoroutinesModule.kt
new file mode 100644
index 0000000..a13d85b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/kotlin/SysUICoroutinesModule.kt
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.util.kotlin
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.dagger.qualifiers.Tracing
+import dagger.Module
+import dagger.Provides
+import kotlin.coroutines.CoroutineContext
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.plus
+
+/** Providers for various SystemIU specific coroutines-related constructs. */
+@Module
+class SysUICoroutinesModule {
+ @Provides
+ @SysUISingleton
+ @Background
+ fun bgApplicationScope(
+ @Application applicationScope: CoroutineScope,
+ @Background coroutineContext: CoroutineContext,
+ ): CoroutineScope = applicationScope.plus(coroutineContext)
+
+ /**
+ * Provide a [CoroutineDispatcher] backed by a thread pool containing at most X threads, where X
+ * is the number of CPU cores available.
+ *
+ * Because there are multiple threads at play, there is no serialization order guarantee. You
+ * should use a [kotlinx.coroutines.channels.Channel] for serialization if necessary.
+ *
+ * @see Dispatchers.Default
+ */
+ @Provides
+ @SysUISingleton
+ @Background
+ @Deprecated(
+ "Use @Background CoroutineContext instead",
+ ReplaceWith("bgCoroutineContext()", "kotlin.coroutines.CoroutineContext")
+ )
+ fun bgDispatcher(): CoroutineDispatcher = Dispatchers.IO
+
+ @Provides
+ @Background
+ @SysUISingleton
+ fun bgCoroutineContext(@Tracing tracingCoroutineContext: CoroutineContext): CoroutineContext {
+ return Dispatchers.IO + tracingCoroutineContext
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dagger/AudioModule.kt b/packages/SystemUI/src/com/android/systemui/volume/dagger/AudioModule.kt
new file mode 100644
index 0000000..8d5e55a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/volume/dagger/AudioModule.kt
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.volume.dagger
+
+import android.media.AudioManager
+import com.android.settingslib.volume.data.repository.AudioRepository
+import com.android.settingslib.volume.data.repository.AudioRepositoryImpl
+import com.android.settingslib.volume.domain.interactor.AudioModeInteractor
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.Background
+import dagger.Module
+import dagger.Provides
+import kotlin.coroutines.CoroutineContext
+import kotlinx.coroutines.CoroutineScope
+
+/** Dagger module for audio code in the volume package */
+@Module
+interface AudioModule {
+
+ companion object {
+
+ @Provides
+ fun provideAudioRepository(
+ audioManager: AudioManager,
+ @Background coroutineContext: CoroutineContext,
+ @Application coroutineScope: CoroutineScope,
+ ): AudioRepository = AudioRepositoryImpl(audioManager, coroutineContext, coroutineScope)
+
+ @Provides
+ fun provideAudioModeInteractor(repository: AudioRepository): AudioModeInteractor =
+ AudioModeInteractor(repository)
+ }
+}
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 b1bfbe0..c842e5f 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dagger/VolumeModule.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/dagger/VolumeModule.java
@@ -60,6 +60,9 @@
/** Dagger Module for code in the volume package. */
@Module(
+ includes = {
+ AudioModule.class,
+ },
subcomponents = {
VolumePanelComponent.class
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
index 044881e..04aef82 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
@@ -92,6 +92,7 @@
import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.animation.AnimatorTestRule;
+import com.android.systemui.kosmos.KosmosJavaAdapter;
import com.android.systemui.model.SysUiState;
import com.android.systemui.res.R;
import com.android.systemui.settings.FakeDisplayTracker;
@@ -159,6 +160,7 @@
private View mSpyView;
private View.OnTouchListener mTouchListener;
private MotionEventHelper mMotionEventHelper = new MotionEventHelper();
+ private KosmosJavaAdapter mKosmos;
/**
* return whether window magnification is supported for current test context.
@@ -170,6 +172,7 @@
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
+ mKosmos = new KosmosJavaAdapter(this);
mContext = Mockito.spy(getContext());
mHandler = new FakeHandler(TestableLooper.get(this).getLooper());
mInstrumentation = InstrumentationRegistry.getInstrumentation();
@@ -185,7 +188,7 @@
return null;
}).when(mSfVsyncFrameProvider).postFrameCallback(
any(FrameCallback.class));
- mSysUiState = new SysUiState(mDisplayTracker);
+ mSysUiState = new SysUiState(mDisplayTracker, mKosmos.getSceneContainerPlugin());
mSysUiState.addCallback(Mockito.mock(SysUiState.SysUiStateCallback.class));
when(mSecureSettings.getIntForUser(anyString(), anyInt(), anyInt())).then(
returnsSecondArg());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerTest.java
index 4a1bdbc..ca3eb3e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerTest.java
@@ -69,6 +69,7 @@
import androidx.dynamicanimation.animation.SpringAnimation;
import androidx.test.filters.SmallTest;
+import com.android.internal.accessibility.common.ShortcutConstants;
import com.android.internal.messages.nano.SystemMessageProto;
import com.android.systemui.Flags;
import com.android.systemui.SysuiTestCase;
@@ -237,7 +238,7 @@
final List<String> stubShortcutTargets = new ArrayList<>();
stubShortcutTargets.add(TEST_SELECT_TO_SPEAK_COMPONENT_NAME.flattenToString());
when(mStubAccessibilityManager.getAccessibilityShortcutTargets(
- AccessibilityManager.ACCESSIBILITY_SHORTCUT_KEY)).thenReturn(stubShortcutTargets);
+ ShortcutConstants.UserShortcutType.HARDWARE)).thenReturn(stubShortcutTargets);
mMenuViewLayer.mDismissMenuAction.run();
final String value = Settings.Secure.getString(mSpyContext.getContentResolver(),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyboard/stickykeys/data/repository/StickyKeysRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyboard/stickykeys/data/repository/StickyKeysRepositoryImplTest.kt
new file mode 100644
index 0000000..ed80a86
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyboard/stickykeys/data/repository/StickyKeysRepositoryImplTest.kt
@@ -0,0 +1,98 @@
+package com.android.systemui.keyboard.stickykeys.data.repository
+
+import android.content.pm.UserInfo
+import android.hardware.input.InputManager
+import android.provider.Settings.Secure.ACCESSIBILITY_STICKY_KEYS
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.coroutines.collectValues
+import com.android.systemui.keyboard.stickykeys.StickyKeysLogger
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.user.data.repository.fakeUserRepository
+import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.settings.FakeSettings
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.StandardTestDispatcher
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(JUnit4::class)
+class StickyKeysRepositoryImplTest : SysuiTestCase() {
+
+ private val dispatcher = StandardTestDispatcher()
+ private val testScope = TestScope(dispatcher)
+ private val secureSettings = FakeSettings()
+ private val userRepository = Kosmos().fakeUserRepository
+ private lateinit var stickyKeysRepository: StickyKeysRepositoryImpl
+
+ @Before
+ fun setup() {
+ stickyKeysRepository = StickyKeysRepositoryImpl(
+ mock<InputManager>(),
+ dispatcher,
+ secureSettings,
+ userRepository,
+ mock<StickyKeysLogger>()
+ )
+ userRepository.setUserInfos(USER_INFOS)
+ setStickyKeySettingForUser(enabled = true, userInfo = SETTING_ENABLED_USER)
+ setStickyKeySettingForUser(enabled = false, userInfo = SETTING_DISABLED_USER)
+ }
+
+ @Test
+ fun settingEnabledEmitsValueForCurrentUser() {
+ testScope.runTest {
+ userRepository.setSelectedUserInfo(SETTING_ENABLED_USER)
+
+ val enabled by collectLastValue(stickyKeysRepository.settingEnabled)
+
+ assertThat(enabled).isTrue()
+ }
+ }
+
+ @Test
+ fun settingEnabledEmitsNewValueWhenSettingChanges() {
+ testScope.runTest {
+ userRepository.setSelectedUserInfo(SETTING_ENABLED_USER)
+ val enabled by collectValues(stickyKeysRepository.settingEnabled)
+ runCurrent()
+
+ setStickyKeySettingForUser(enabled = false, userInfo = SETTING_ENABLED_USER)
+
+ assertThat(enabled).containsExactly(true, false).inOrder()
+ }
+ }
+
+ @Test
+ fun settingEnabledEmitsValueForNewUserWhenUserChanges() {
+ testScope.runTest {
+ userRepository.setSelectedUserInfo(SETTING_ENABLED_USER)
+ val enabled by collectLastValue(stickyKeysRepository.settingEnabled)
+ runCurrent()
+
+ userRepository.setSelectedUserInfo(SETTING_DISABLED_USER)
+
+ assertThat(enabled).isFalse()
+ }
+ }
+
+ private fun setStickyKeySettingForUser(enabled: Boolean, userInfo: UserInfo) {
+ val newValue = if (enabled) "1" else "0"
+ secureSettings.putStringForUser(ACCESSIBILITY_STICKY_KEYS, newValue, userInfo.id)
+ }
+
+ private companion object {
+ val SETTING_ENABLED_USER = UserInfo(/* id= */ 0, "user1", /* flags= */ 0)
+ val SETTING_DISABLED_USER = UserInfo(/* id= */ 1, "user2", /* flags= */ 0)
+ val USER_INFOS = listOf(SETTING_ENABLED_USER, SETTING_DISABLED_USER)
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyboard/stickykeys/ui/viewmodel/StickyKeysIndicatorViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyboard/stickykeys/ui/viewmodel/StickyKeysIndicatorViewModelTest.kt
index 8a71368..6eebb6d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyboard/stickykeys/ui/viewmodel/StickyKeysIndicatorViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyboard/stickykeys/ui/viewmodel/StickyKeysIndicatorViewModelTest.kt
@@ -18,6 +18,7 @@
import android.hardware.input.InputManager
import android.hardware.input.StickyModifierState
+import android.provider.Settings.Secure.ACCESSIBILITY_STICKY_KEYS
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
@@ -31,8 +32,11 @@
import com.android.systemui.keyboard.stickykeys.shared.model.ModifierKey.CTRL
import com.android.systemui.keyboard.stickykeys.shared.model.ModifierKey.META
import com.android.systemui.keyboard.stickykeys.shared.model.ModifierKey.SHIFT
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.user.data.repository.fakeUserRepository
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.settings.FakeSettings
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.StandardTestDispatcher
@@ -57,6 +61,8 @@
private lateinit var viewModel: StickyKeysIndicatorViewModel
private val inputManager = mock<InputManager>()
private val keyboardRepository = FakeKeyboardRepository()
+ private val secureSettings = FakeSettings()
+ private val userRepository = Kosmos().fakeUserRepository
private val captor =
ArgumentCaptor.forClass(InputManager.StickyModifierStateListener::class.java)
@@ -65,8 +71,11 @@
val stickyKeysRepository = StickyKeysRepositoryImpl(
inputManager,
dispatcher,
+ secureSettings,
+ userRepository,
mock<StickyKeysLogger>()
)
+ setStickyKeySetting(enabled = false)
viewModel =
StickyKeysIndicatorViewModel(
stickyKeysRepository = stickyKeysRepository,
@@ -76,15 +85,26 @@
}
@Test
- fun startsListeningToStickyKeysOnlyWhenKeyboardIsConnected() {
+ fun doesntListenToStickyKeysOnlyWhenKeyboardIsConnected() {
testScope.runTest {
collectLastValue(viewModel.indicatorContent)
- runCurrent()
- verifyZeroInteractions(inputManager)
keyboardRepository.setIsAnyKeyboardConnected(true)
runCurrent()
+ verifyZeroInteractions(inputManager)
+ }
+ }
+
+ @Test
+ fun startsListeningToStickyKeysOnlyWhenKeyboardIsConnectedAndSettingIsOn() {
+ testScope.runTest {
+ collectLastValue(viewModel.indicatorContent)
+ keyboardRepository.setIsAnyKeyboardConnected(true)
+
+ setStickyKeySetting(enabled = true)
+ runCurrent()
+
verify(inputManager)
.registerStickyModifierStateListener(
any(),
@@ -93,11 +113,31 @@
}
}
+ private fun setStickyKeySetting(enabled: Boolean) {
+ val newValue = if (enabled) "1" else "0"
+ val defaultUser = userRepository.getSelectedUserInfo().id
+ secureSettings.putStringForUser(ACCESSIBILITY_STICKY_KEYS, newValue, defaultUser)
+ }
+
+ @Test
+ fun stopsListeningToStickyKeysWhenStickyKeySettingsIsTurnedOff() {
+ testScope.runTest {
+ collectLastValue(viewModel.indicatorContent)
+ setStickyKeysActive()
+ runCurrent()
+
+ setStickyKeySetting(enabled = false)
+ runCurrent()
+
+ verify(inputManager).unregisterStickyModifierStateListener(any())
+ }
+ }
+
@Test
fun stopsListeningToStickyKeysWhenKeyboardDisconnects() {
testScope.runTest {
collectLastValue(viewModel.indicatorContent)
- keyboardRepository.setIsAnyKeyboardConnected(true)
+ setStickyKeysActive()
runCurrent()
keyboardRepository.setIsAnyKeyboardConnected(false)
@@ -111,7 +151,7 @@
fun emitsStickyKeysListWhenStickyKeyIsPressed() {
testScope.runTest {
val stickyKeys by collectLastValue(viewModel.indicatorContent)
- keyboardRepository.setIsAnyKeyboardConnected(true)
+ setStickyKeysActive()
setStickyKeys(mapOf(ALT to false))
@@ -123,7 +163,7 @@
fun emitsEmptyListWhenNoStickyKeysAreActive() {
testScope.runTest {
val stickyKeys by collectLastValue(viewModel.indicatorContent)
- keyboardRepository.setIsAnyKeyboardConnected(true)
+ setStickyKeysActive()
setStickyKeys(emptyMap())
@@ -135,7 +175,7 @@
fun passesAllStickyKeysToDialog() {
testScope.runTest {
val stickyKeys by collectLastValue(viewModel.indicatorContent)
- keyboardRepository.setIsAnyKeyboardConnected(true)
+ setStickyKeysActive()
setStickyKeys(mapOf(
ALT to false,
@@ -154,7 +194,7 @@
fun showsOnlyLockedStateIfKeyIsStickyAndLocked() {
testScope.runTest {
val stickyKeys by collectLastValue(viewModel.indicatorContent)
- keyboardRepository.setIsAnyKeyboardConnected(true)
+ setStickyKeysActive()
setStickyKeys(mapOf(
ALT to false,
@@ -168,7 +208,7 @@
fun doesNotChangeOrderOfKeysIfTheyBecomeLocked() {
testScope.runTest {
val stickyKeys by collectLastValue(viewModel.indicatorContent)
- keyboardRepository.setIsAnyKeyboardConnected(true)
+ setStickyKeysActive()
setStickyKeys(mapOf(
META to false,
@@ -186,6 +226,11 @@
}
}
+ private fun setStickyKeysActive() {
+ keyboardRepository.setIsAnyKeyboardConnected(true)
+ setStickyKeySetting(enabled = true)
+ }
+
private fun TestScope.setStickyKeys(keys: Map<ModifierKey, Boolean>) {
runCurrent()
verify(inputManager).registerStickyModifierStateListener(any(), captor.capture())
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
index 1183964..14cae0b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
@@ -357,6 +357,7 @@
mock(FoldGracePeriodProvider.class);
mViewMediator.mFoldGracePeriodProvider = mockedFoldGracePeriodProvider;
when(mockedFoldGracePeriodProvider.isEnabled()).thenReturn(true);
+ when(mUpdateMonitor.isDeviceProvisioned()).thenReturn(true);
// GIVEN keyguard is not enabled and isn't showing
mViewMediator.onSystemReady();
@@ -375,12 +376,40 @@
@Test
@TestableLooper.RunWithLooper(setAsMainLooper = true)
+ public void doNotShowKeyguard_deviceNotProvisioned() {
+ // GIVEN feature is enabled
+ final FoldGracePeriodProvider mockedFoldGracePeriodProvider =
+ mock(FoldGracePeriodProvider.class);
+ mViewMediator.mFoldGracePeriodProvider = mockedFoldGracePeriodProvider;
+ when(mockedFoldGracePeriodProvider.isEnabled()).thenReturn(true);
+
+ // GIVEN keyguard is not enabled and isn't showing
+ mViewMediator.onSystemReady();
+ mViewMediator.setKeyguardEnabled(false);
+ TestableLooper.get(this).processAllMessages();
+ captureKeyguardUpdateMonitorCallback();
+ assertFalse(mViewMediator.isShowingAndNotOccluded());
+
+ // WHEN device is NOT provisioned
+ when(mUpdateMonitor.isDeviceProvisioned()).thenReturn(false);
+
+ // WHEN showKeyguard is requested
+ mViewMediator.showDismissibleKeyguard();
+
+ // THEN keyguard is NOT shown
+ TestableLooper.get(this).processAllMessages();
+ assertFalse(mViewMediator.isShowingAndNotOccluded());
+ }
+
+ @Test
+ @TestableLooper.RunWithLooper(setAsMainLooper = true)
public void showKeyguardAfterKeyguardNotEnabled_featureNotEnabled() {
// GIVEN feature is NOT enabled
final FoldGracePeriodProvider mockedFoldGracePeriodProvider =
mock(FoldGracePeriodProvider.class);
mViewMediator.mFoldGracePeriodProvider = mockedFoldGracePeriodProvider;
when(mockedFoldGracePeriodProvider.isEnabled()).thenReturn(false);
+ when(mUpdateMonitor.isDeviceProvisioned()).thenReturn(true);
// GIVEN keyguard is not enabled and isn't showing
mViewMediator.onSystemReady();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/model/SysUiStateExtTest.kt b/packages/SystemUI/tests/src/com/android/systemui/model/SysUiStateExtTest.kt
index f5a70f0..8e05410 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/model/SysUiStateExtTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/model/SysUiStateExtTest.kt
@@ -20,6 +20,7 @@
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.settings.FakeDisplayTracker
+import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
import org.junit.Test
import org.junit.runner.RunWith
@@ -29,7 +30,13 @@
@RunWith(JUnit4::class)
class SysUiStateExtTest : SysuiTestCase() {
- private val underTest = SysUiState(FakeDisplayTracker(context))
+ private val kosmos = testKosmos()
+
+ private val underTest =
+ SysUiState(
+ FakeDisplayTracker(context),
+ kosmos.sceneContainerPlugin,
+ )
@Test
fun updateFlags() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/model/SysUiStateTest.java b/packages/SystemUI/tests/src/com/android/systemui/model/SysUiStateTest.java
index 1a93adc..f03f4f7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/model/SysUiStateTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/model/SysUiStateTest.java
@@ -26,6 +26,7 @@
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.kosmos.KosmosJavaAdapter;
import com.android.systemui.settings.FakeDisplayTracker;
import org.junit.Before;
@@ -42,13 +43,15 @@
private static final int FLAG_4 = 1 << 3;
private static final int DISPLAY_ID = DEFAULT_DISPLAY;
+ private KosmosJavaAdapter mKosmos;
private SysUiState.SysUiStateCallback mCallback;
private SysUiState mFlagsContainer;
@Before
public void setup() {
FakeDisplayTracker displayTracker = new FakeDisplayTracker(mContext);
- mFlagsContainer = new SysUiState(displayTracker);
+ mKosmos = new KosmosJavaAdapter(this);
+ mFlagsContainer = new SysUiState(displayTracker, mKosmos.getSceneContainerPlugin());
mCallback = mock(SysUiState.SysUiStateCallback.class);
mFlagsContainer.addCallback(mCallback);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavBarHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavBarHelperTest.java
index 8d306cce..28d35ce 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavBarHelperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavBarHelperTest.java
@@ -41,6 +41,7 @@
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.internal.accessibility.common.ShortcutConstants;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.accessibility.AccessibilityButtonModeObserver;
import com.android.systemui.accessibility.AccessibilityButtonTargetsObserver;
@@ -56,6 +57,8 @@
import com.android.systemui.statusbar.phone.CentralSurfaces;
import com.android.systemui.statusbar.policy.KeyguardStateController;
+import dagger.Lazy;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -65,8 +68,7 @@
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
-
-import dagger.Lazy;
+import java.util.concurrent.Executor;
/**
* Tests for {@link NavBarHelper}.
@@ -123,6 +125,8 @@
SYSUI_STATE_A11Y_BUTTON_CLICKABLE | SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE;
private NavBarHelper mNavBarHelper;
+ private final Executor mSynchronousExecutor = runnable -> runnable.run();
+
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
@@ -140,7 +144,8 @@
mSystemActions, mOverviewProxyService, mAssistManagerLazy,
() -> Optional.of(mock(CentralSurfaces.class)), mock(KeyguardStateController.class),
mNavigationModeController, mEdgeBackGestureHandlerFactory, mWm, mUserTracker,
- mDisplayTracker, mNotificationShadeWindowController, mDumpManager, mCommandQueue);
+ mDisplayTracker, mNotificationShadeWindowController, mDumpManager, mCommandQueue,
+ mSynchronousExecutor);
}
@@ -266,7 +271,8 @@
@Test
public void initNavBarHelper_buttonModeNavBar_a11yButtonClickableState() {
when(mAccessibilityManager.getAccessibilityShortcutTargets(
- AccessibilityManager.ACCESSIBILITY_BUTTON)).thenReturn(createFakeShortcutTargets());
+ ShortcutConstants.UserShortcutType.SOFTWARE)).thenReturn(
+ createFakeShortcutTargets());
mNavBarHelper.registerNavTaskStateUpdater(mNavbarTaskbarStateUpdater);
@@ -291,7 +297,8 @@
ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR);
when(mAccessibilityManager.getAccessibilityShortcutTargets(
- AccessibilityManager.ACCESSIBILITY_BUTTON)).thenReturn(createFakeShortcutTargets());
+ ShortcutConstants.UserShortcutType.SOFTWARE)).thenReturn(
+ createFakeShortcutTargets());
mAccessibilityServicesStateChangeListener.onAccessibilityServicesStateChanged(
mAccessibilityManager);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
index ddceed6..db5bd9b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
@@ -228,6 +228,8 @@
@Rule
public final LeakCheckedTest.SysuiLeakCheck mLeakCheck = new LeakCheckedTest.SysuiLeakCheck();
+ private final Executor mSynchronousExecutor = runnable -> runnable.run();
+
@Before
public void setup() throws Exception {
MockitoAnnotations.initMocks(this);
@@ -269,7 +271,7 @@
mEdgeBackGestureHandlerFactory, mock(IWindowManager.class),
mock(UserTracker.class), mock(DisplayTracker.class),
mNotificationShadeWindowController, mock(DumpManager.class),
- mock(CommandQueue.class)));
+ mock(CommandQueue.class), mSynchronousExecutor));
mNavigationBar = createNavBar(mContext);
mExternalDisplayNavigationBar = createNavBar(mSysuiTestableContextExternal);
});
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/LeftRightArrowPressedListenerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/LeftRightArrowPressedListenerTest.kt
index 60eb3ae..40eccad 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/LeftRightArrowPressedListenerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/LeftRightArrowPressedListenerTest.kt
@@ -37,7 +37,7 @@
object : Consumer<Int> {
var lastValue: Int? = null
- override fun accept(keyCode: Int?) {
+ override fun accept(keyCode: Int) {
lastValue = keyCode
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.kt b/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.kt
index e9f2132..10d6ebf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.kt
@@ -17,16 +17,21 @@
package com.android.systemui.recents
import android.content.ComponentName
+import android.content.Context
import android.content.pm.PackageManager
import android.content.pm.ResolveInfo
import android.os.PowerManager
+import android.os.Process;
+import android.os.UserHandle
import android.testing.AndroidTestingRunner
import android.testing.TestableContext
import android.testing.TestableLooper
import androidx.test.filters.SmallTest
+import com.android.dx.mockito.inline.extended.ExtendedMockito
import com.android.internal.app.AssistUtils
import com.android.internal.logging.UiEventLogger
import com.android.systemui.SysuiTestCase
+import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.dump.DumpManager
import com.android.systemui.flags.FakeFeatureFlags
@@ -35,6 +40,7 @@
import com.android.systemui.keyguard.WakefulnessLifecycle
import com.android.systemui.keyguard.ui.view.InWindowLauncherUnlockAnimationManager
import com.android.systemui.model.SysUiState
+import com.android.systemui.model.sceneContainerPlugin
import com.android.systemui.navigationbar.NavigationBarController
import com.android.systemui.navigationbar.NavigationModeController
import com.android.systemui.recents.OverviewProxyService.ACTION_QUICKSTEP
@@ -50,6 +56,7 @@
import com.android.systemui.shared.system.QuickStepContract.WAKEFULNESS_WAKING
import com.android.systemui.statusbar.CommandQueue
import com.android.systemui.statusbar.NotificationShadeWindowController
+import com.android.systemui.testKosmos
import com.android.systemui.unfold.progress.UnfoldTransitionProgressForwarder
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
@@ -66,10 +73,14 @@
import org.mockito.Mock
import org.mockito.Mockito.any
import org.mockito.Mockito.anyInt
+import org.mockito.Mockito.atLeast
import org.mockito.Mockito.clearInvocations
import org.mockito.Mockito.intThat
import org.mockito.Mockito.mock
+import org.mockito.Mockito.spy
+import org.mockito.Mockito.times
import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when`
import org.mockito.MockitoAnnotations
@SmallTest
@@ -79,11 +90,12 @@
@Main private val executor: Executor = MoreExecutors.directExecutor()
+ private val kosmos = testKosmos()
private lateinit var subject: OverviewProxyService
- private val dumpManager = DumpManager()
+ @Mock private val dumpManager = DumpManager()
private val displayTracker = FakeDisplayTracker(mContext)
private val fakeSystemClock = FakeSystemClock()
- private val sysUiState = SysUiState(displayTracker)
+ private val sysUiState = SysUiState(displayTracker, kosmos.sceneContainerPlugin)
private val featureFlags = FakeFeatureFlags()
private val wakefulnessLifecycle =
WakefulnessLifecycle(mContext, null, fakeSystemClock, dumpManager)
@@ -109,6 +121,8 @@
@Mock
private lateinit var unfoldTransitionProgressForwarder:
Optional<UnfoldTransitionProgressForwarder>
+ @Mock
+ private lateinit var broadcastDispatcher: BroadcastDispatcher
@Before
fun setUp() {
@@ -135,31 +149,7 @@
com.android.systemui.Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR,
)
- subject =
- OverviewProxyService(
- context,
- executor,
- commandQueue,
- shellInterface,
- { navBarController },
- { shadeViewController },
- screenPinningRequest,
- navModeController,
- statusBarWinController,
- sysUiState,
- mock(),
- userTracker,
- wakefulnessLifecycle,
- uiEventLogger,
- displayTracker,
- sysuiUnlockAnimationController,
- inWindowLauncherUnlockAnimationManager,
- assistUtils,
- featureFlags,
- FakeSceneContainerFlags(),
- dumpManager,
- unfoldTransitionProgressForwarder
- )
+ subject = createOverviewProxyService(context)
}
@After
@@ -212,4 +202,66 @@
intThat { it and SYSUI_STATE_WAKEFULNESS_MASK == WAKEFULNESS_GOING_TO_SLEEP }
)
}
+
+ @Test
+ fun connectToOverviewService_primaryUser_expectBindService() {
+ val mockitoSession = ExtendedMockito.mockitoSession()
+ .spyStatic(Process::class.java)
+ .startMocking()
+ try {
+ `when`(Process.myUserHandle()).thenReturn(UserHandle.SYSTEM)
+ val spyContext = spy(context)
+ val ops = createOverviewProxyService(spyContext)
+ ops.startConnectionToCurrentUser()
+ verify(spyContext, atLeast(1)).bindServiceAsUser(any(), any(),
+ anyInt(), any())
+ } finally {
+ mockitoSession.finishMocking()
+ }
+ }
+
+ @Test
+ fun connectToOverviewService_nonPrimaryUser_expectNoBindService() {
+ val mockitoSession = ExtendedMockito.mockitoSession()
+ .spyStatic(Process::class.java)
+ .startMocking()
+ try {
+ `when`(Process.myUserHandle()).thenReturn(UserHandle.of(12345))
+ val spyContext = spy(context)
+ val ops = createOverviewProxyService(spyContext)
+ ops.startConnectionToCurrentUser()
+ verify(spyContext, times(0)).bindServiceAsUser(any(), any(),
+ anyInt(), any())
+ } finally {
+ mockitoSession.finishMocking()
+ }
+ }
+
+ private fun createOverviewProxyService(ctx: Context) : OverviewProxyService {
+ return OverviewProxyService(
+ ctx,
+ executor,
+ commandQueue,
+ shellInterface,
+ { navBarController },
+ { shadeViewController },
+ screenPinningRequest,
+ navModeController,
+ statusBarWinController,
+ sysUiState,
+ mock(),
+ userTracker,
+ wakefulnessLifecycle,
+ uiEventLogger,
+ displayTracker,
+ sysuiUnlockAnimationController,
+ inWindowLauncherUnlockAnimationManager,
+ assistUtils,
+ featureFlags,
+ FakeSceneContainerFlags(),
+ dumpManager,
+ unfoldTransitionProgressForwarder,
+ broadcastDispatcher
+ )
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java
index a2aed98..9ce77e5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java
@@ -28,10 +28,10 @@
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
+import android.app.ActivityOptions.LaunchCookie;
import android.app.Notification;
import android.app.NotificationManager;
import android.content.Intent;
-import android.os.Binder;
import android.os.Handler;
import android.os.RemoteException;
import android.os.UserHandle;
@@ -146,7 +146,7 @@
@Test
public void testLogStartPartialRecording() {
- MediaProjectionCaptureTarget target = new MediaProjectionCaptureTarget(new Binder());
+ MediaProjectionCaptureTarget target = new MediaProjectionCaptureTarget(new LaunchCookie());
Intent startIntent = RecordingService.getStartIntent(mContext, 0, 0, false, target);
mRecordingService.onStartCommand(startIntent, 0, 0);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
index 6681cee..22b05be 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
@@ -514,7 +514,7 @@
}
whenever(mGlanceableHubContainerController.isEnabled()).thenReturn(false)
- whenever(mGlanceableHubContainerController.enabledState())
+ whenever(mGlanceableHubContainerController.communalAvailable())
.thenReturn(MutableStateFlow(false))
val mockCommunalPlaceholder = mock(View::class.java)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
index 316f2b9..849a13b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
@@ -41,6 +41,8 @@
import static java.util.Collections.emptySet;
+import static kotlinx.coroutines.flow.FlowKt.flowOf;
+
import android.app.ActivityManager;
import android.app.IWallpaperManager;
import android.app.WallpaperManager;
@@ -72,13 +74,11 @@
import androidx.test.filters.SmallTest;
import com.android.internal.colorextraction.ColorExtractor;
-import com.android.internal.jank.InteractionJankMonitor;
import com.android.internal.logging.UiEventLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.logging.testing.FakeMetricsLogger;
import com.android.internal.statusbar.IStatusBarService;
import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.keyguard.TestScopeProvider;
import com.android.keyguard.ViewMediatorCallback;
import com.android.systemui.InitController;
import com.android.systemui.SysuiTestCase;
@@ -93,6 +93,10 @@
import com.android.systemui.classifier.FalsingCollectorFake;
import com.android.systemui.classifier.FalsingManagerFake;
import com.android.systemui.colorextraction.SysuiColorExtractor;
+import com.android.systemui.communal.data.repository.CommunalRepository;
+import com.android.systemui.communal.domain.interactor.CommunalInteractor;
+import com.android.systemui.communal.shared.model.CommunalSceneKey;
+import com.android.systemui.communal.shared.model.ObservableCommunalTransitionState;
import com.android.systemui.demomode.DemoModeController;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FakeFeatureFlags;
@@ -103,6 +107,7 @@
import com.android.systemui.keyguard.ScreenLifecycle;
import com.android.systemui.keyguard.WakefulnessLifecycle;
import com.android.systemui.keyguard.ui.viewmodel.LightRevealScrimViewModel;
+import com.android.systemui.kosmos.KosmosJavaAdapter;
import com.android.systemui.log.LogBuffer;
import com.android.systemui.navigationbar.NavigationBarController;
import com.android.systemui.notetask.NoteTaskController;
@@ -131,7 +136,6 @@
import com.android.systemui.statusbar.KeyguardIndicationController;
import com.android.systemui.statusbar.LightRevealScrim;
import com.android.systemui.statusbar.LockscreenShadeTransitionController;
-import com.android.systemui.statusbar.NotificationListener;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationMediaManager;
import com.android.systemui.statusbar.NotificationPresenter;
@@ -144,13 +148,10 @@
import com.android.systemui.statusbar.StatusBarStateControllerImpl;
import com.android.systemui.statusbar.core.StatusBarInitializer;
import com.android.systemui.statusbar.data.repository.FakeStatusBarModeRepository;
-import com.android.systemui.statusbar.notification.DynamicPrivacyController;
import com.android.systemui.statusbar.notification.NotifPipelineFlags;
import com.android.systemui.statusbar.notification.NotificationActivityStarter;
import com.android.systemui.statusbar.notification.NotificationLaunchAnimatorControllerProvider;
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
-import com.android.systemui.statusbar.notification.collection.NotifLiveDataStore;
-import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider;
import com.android.systemui.statusbar.notification.init.NotificationsController;
import com.android.systemui.statusbar.notification.interruption.KeyguardNotificationVisibilityProvider;
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptLogger;
@@ -169,7 +170,6 @@
import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.statusbar.policy.UserInfoControllerImpl;
-import com.android.systemui.statusbar.policy.UserSwitcherController;
import com.android.systemui.statusbar.window.StatusBarWindowController;
import com.android.systemui.statusbar.window.StatusBarWindowStateController;
import com.android.systemui.util.EventLog;
@@ -201,6 +201,8 @@
import javax.inject.Provider;
+import kotlinx.coroutines.test.TestScope;
+
@SmallTest
@RunWith(AndroidTestingRunner.class)
@RunWithLooper(setAsMainLooper = true)
@@ -209,11 +211,17 @@
private static final int FOLD_STATE_FOLDED = 0;
private static final int FOLD_STATE_UNFOLDED = 1;
+ private final KosmosJavaAdapter mKosmos = new KosmosJavaAdapter(this);
+
private CentralSurfacesImpl mCentralSurfaces;
private FakeMetricsLogger mMetricsLogger;
private PowerManager mPowerManager;
private VisualInterruptionDecisionProvider mVisualInterruptionDecisionProvider;
+
+ private final TestScope mTestScope = mKosmos.getTestScope();
+ private final CommunalInteractor mCommunalInteractor = mKosmos.getCommunalInteractor();
+ private final CommunalRepository mCommunalRepository = mKosmos.getCommunalRepository();
@Mock private NotificationsController mNotificationsController;
@Mock private LightBarController mLightBarController;
@Mock private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
@@ -235,12 +243,10 @@
@Mock private Lazy<BiometricUnlockController> mBiometricUnlockControllerLazy;
@Mock private BiometricUnlockController mBiometricUnlockController;
@Mock private AuthRippleController mAuthRippleController;
- @Mock private NotificationListener mNotificationListener;
@Mock private KeyguardViewMediator mKeyguardViewMediator;
@Mock private NotificationLockscreenUserManager mLockscreenUserManager;
@Mock private NotificationRemoteInputManager mRemoteInputManager;
@Mock private StatusBarStateControllerImpl mStatusBarStateController;
- @Mock private ShadeExpansionStateManager mShadeExpansionStateManager;
@Mock private BatteryController mBatteryController;
@Mock private DeviceProvisionedController mDeviceProvisionedController;
@Mock private NotificationLaunchAnimatorControllerProvider mNotifLaunchAnimControllerProvider;
@@ -262,12 +268,10 @@
@Mock private PulseExpansionHandler mPulseExpansionHandler;
@Mock private NotificationWakeUpCoordinator mNotificationWakeUpCoordinator;
@Mock private KeyguardBypassController mKeyguardBypassController;
- @Mock private DynamicPrivacyController mDynamicPrivacyController;
@Mock private AutoHideController mAutoHideController;
@Mock private StatusBarWindowController mStatusBarWindowController;
@Mock private Provider<CollapsedStatusBarFragment> mCollapsedStatusBarFragmentProvider;
@Mock private StatusBarWindowStateController mStatusBarWindowStateController;
- @Mock private UserSwitcherController mUserSwitcherController;
@Mock private Bubbles mBubbles;
@Mock private NoteTaskController mNoteTaskController;
@Mock private NotificationShadeWindowController mNotificationShadeWindowController;
@@ -295,7 +299,6 @@
@Mock private WallpaperController mWallpaperController;
@Mock private StatusBarHideIconsForBouncerManager mStatusBarHideIconsForBouncerManager;
@Mock private LockscreenShadeTransitionController mLockscreenTransitionController;
- @Mock private NotificationVisibilityProvider mVisibilityProvider;
@Mock private WallpaperManager mWallpaperManager;
@Mock private IWallpaperManager mIWallpaperManager;
@Mock private KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
@@ -304,8 +307,6 @@
@Mock private OperatorNameViewController mOperatorNameViewController;
@Mock private OperatorNameViewController.Factory mOperatorNameViewControllerFactory;
@Mock private ActivityLaunchAnimator mActivityLaunchAnimator;
- @Mock private NotifLiveDataStore mNotifLiveDataStore;
- @Mock private InteractionJankMonitor mJankMonitor;
@Mock private DeviceStateManager mDeviceStateManager;
@Mock private WiredChargingRippleController mWiredChargingRippleController;
@Mock private Lazy<CameraLauncher> mCameraLauncherLazy;
@@ -465,30 +466,28 @@
mKeyguardBypassController,
mKeyguardStateController,
mHeadsUpManager,
- mDynamicPrivacyController,
new FalsingManagerFake(),
new FalsingCollectorFake(),
mBroadcastDispatcher,
mNotificationGutsManager,
- mVisualInterruptionDecisionProvider,
new ShadeExpansionStateManager(),
mKeyguardViewMediator,
new DisplayMetrics(),
mMetricsLogger,
mShadeLogger,
- new JavaAdapter(TestScopeProvider.getTestScope()),
+ new JavaAdapter(mTestScope),
mUiBgExecutor,
mNotificationPanelViewController,
mNotificationMediaManager,
mLockscreenUserManager,
mRemoteInputManager,
mQuickSettingsController,
- mUserSwitcherController,
mBatteryController,
mColorExtractor,
mScreenLifecycle,
mWakefulnessLifecycle,
mPowerInteractor,
+ mCommunalInteractor,
mStatusBarStateController,
Optional.of(mBubbles),
() -> mNoteTaskController,
@@ -542,7 +541,6 @@
mWallpaperManager,
Optional.of(mStartingSurface),
mActivityLaunchAnimator,
- mJankMonitor,
mDeviceStateManager,
mWiredChargingRippleController,
mDreamManager,
@@ -838,6 +836,25 @@
}
@Test
+ public void testEnteringGlanceableHub_updatesScrim() {
+ // Transition to the glanceable hub.
+ mCommunalRepository.setTransitionState(flowOf(new ObservableCommunalTransitionState.Idle(
+ CommunalSceneKey.Communal.INSTANCE)));
+ mTestScope.getTestScheduler().runCurrent();
+
+ // ScrimState also transitions.
+ verify(mScrimController).transitionTo(ScrimState.GLANCEABLE_HUB);
+
+ // Transition away from the glanceable hub.
+ mCommunalRepository.setTransitionState(flowOf(new ObservableCommunalTransitionState.Idle(
+ CommunalSceneKey.Blank.INSTANCE)));
+ mTestScope.getTestScheduler().runCurrent();
+
+ // ScrimState goes back to UNLOCKED.
+ verify(mScrimController).transitionTo(eq(ScrimState.UNLOCKED), any());
+ }
+
+ @Test
public void testShowKeyguardImplementation_setsState() {
when(mLockscreenUserManager.getCurrentProfiles()).thenReturn(new SparseArray<>());
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 b3a47d7..3bde6e3 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
@@ -31,6 +31,7 @@
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
@@ -50,6 +51,7 @@
import android.graphics.Color;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
+import android.testing.ViewUtils;
import android.util.MathUtils;
import android.view.View;
@@ -58,13 +60,13 @@
import com.android.internal.colorextraction.ColorExtractor.GradientColors;
import com.android.keyguard.BouncerPanelExpansionCalculator;
import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.keyguard.TestScopeProvider;
import com.android.systemui.DejankUtils;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.animation.ShadeInterpolation;
import com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants;
import com.android.systemui.dock.DockManager;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
+import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository;
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
import com.android.systemui.keyguard.shared.model.KeyguardState;
@@ -72,6 +74,7 @@
import com.android.systemui.keyguard.shared.model.TransitionStep;
import com.android.systemui.keyguard.ui.viewmodel.AlternateBouncerToGoneTransitionViewModel;
import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToGoneTransitionViewModel;
+import com.android.systemui.kosmos.KosmosJavaAdapter;
import com.android.systemui.scrim.ScrimView;
import com.android.systemui.shade.transition.LargeScreenShadeInterpolator;
import com.android.systemui.shade.transition.LinearLargeScreenShadeInterpolator;
@@ -102,7 +105,6 @@
import java.util.HashSet;
import java.util.Map;
-import kotlinx.coroutines.CoroutineDispatcher;
import kotlinx.coroutines.test.TestScope;
@RunWith(AndroidTestingRunner.class)
@@ -111,13 +113,14 @@
public class ScrimControllerTest extends SysuiTestCase {
@Rule public Expect mExpect = Expect.create();
+ private final KosmosJavaAdapter mKosmos = new KosmosJavaAdapter(this);
private final FakeConfigurationController mConfigurationController =
new FakeConfigurationController();
private final LargeScreenShadeInterpolator
mLinearLargeScreenShadeInterpolator = new LinearLargeScreenShadeInterpolator();
- private final TestScope mTestScope = TestScopeProvider.getTestScope();
+ private final TestScope mTestScope = mKosmos.getTestScope();
private final JavaAdapter mJavaAdapter = new JavaAdapter(mTestScope.getBackgroundScope());
private ScrimController mScrimController;
@@ -144,10 +147,12 @@
@Mock private PrimaryBouncerToGoneTransitionViewModel mPrimaryBouncerToGoneTransitionViewModel;
@Mock private AlternateBouncerToGoneTransitionViewModel
mAlternateBouncerToGoneTransitionViewModel;
- @Mock private KeyguardTransitionInteractor mKeyguardTransitionInteractor;
+ private final KeyguardTransitionInteractor mKeyguardTransitionInteractor =
+ mKosmos.getKeyguardTransitionInteractor();
+ private final FakeKeyguardTransitionRepository mKeyguardTransitionRepository =
+ mKosmos.getKeyguardTransitionRepository();
@Mock private KeyguardInteractor mKeyguardInteractor;
private final FakeWallpaperRepository mWallpaperRepository = new FakeWallpaperRepository();
- @Mock private CoroutineDispatcher mMainDispatcher;
@Mock private TypedArray mMockTypedArray;
// TODO(b/204991468): Use a real PanelExpansionStateManager object once this bug is fixed. (The
@@ -264,8 +269,6 @@
when(mDelayedWakeLockFactory.create(any(String.class))).thenReturn(mWakeLock);
when(mDockManager.isDocked()).thenReturn(false);
- when(mKeyguardTransitionInteractor.transition(any(), any()))
- .thenReturn(emptyFlow());
when(mPrimaryBouncerToGoneTransitionViewModel.getScrimAlpha())
.thenReturn(emptyFlow());
when(mAlternateBouncerToGoneTransitionViewModel.getScrimAlpha())
@@ -291,13 +294,16 @@
mKeyguardTransitionInteractor,
mKeyguardInteractor,
mWallpaperRepository,
- mMainDispatcher,
+ mKosmos.getTestDispatcher(),
mLinearLargeScreenShadeInterpolator);
mScrimController.start();
mScrimController.setScrimVisibleListener(visible -> mScrimVisibility = visible);
mScrimController.attachViews(mScrimBehind, mNotificationsScrim, mScrimInFront);
mScrimController.setAnimatorListener(mAnimatorListener);
+ // Attach behind scrim so flows that are collecting on it start running.
+ ViewUtils.attachView(mScrimBehind);
+
mScrimController.setHasBackdrop(false);
mWallpaperRepository.getWallpaperSupportsAmbientMode().setValue(false);
@@ -628,6 +634,164 @@
}
@Test
+ public void lockscreenToHubTransition_setsBehindScrimAlpha() {
+ // Start on lockscreen.
+ mScrimController.transitionTo(ScrimState.KEYGUARD);
+ finishAnimationsImmediately();
+
+ // Behind scrim starts at default alpha.
+ final float transitionProgress = 0f;
+ float expectedAlpha = ScrimState.KEYGUARD.getBehindAlpha();
+ mKeyguardTransitionRepository.sendTransitionStepJava(mKosmos.getTestScope(),
+ new TransitionStep(
+ KeyguardState.LOCKSCREEN,
+ KeyguardState.GLANCEABLE_HUB,
+ transitionProgress,
+ TransitionState.STARTED
+ ), true);
+ mTestScope.getTestScheduler().runCurrent();
+ assertThat(mScrimBehind.getViewAlpha()).isEqualTo(expectedAlpha);
+
+ // Scrim fades out as transition runs.
+ final float runningProgress = 0.2f;
+ expectedAlpha = (1 - runningProgress) * ScrimState.KEYGUARD.getBehindAlpha();
+ mKeyguardTransitionRepository.sendTransitionStepJava(mKosmos.getTestScope(),
+ new TransitionStep(
+ KeyguardState.LOCKSCREEN,
+ KeyguardState.GLANCEABLE_HUB,
+ runningProgress,
+ TransitionState.RUNNING
+ ), true);
+ mTestScope.getTestScheduler().runCurrent();
+ assertThat(mScrimBehind.getViewAlpha()).isEqualTo(expectedAlpha);
+
+ // Scrim invisible at end of transition.
+ final float finishedProgress = 1f;
+ expectedAlpha = 0f;
+ mKeyguardTransitionRepository.sendTransitionStepJava(mKosmos.getTestScope(),
+ new TransitionStep(
+ KeyguardState.LOCKSCREEN,
+ KeyguardState.GLANCEABLE_HUB,
+ finishedProgress,
+ TransitionState.FINISHED
+ ), true);
+ mTestScope.getTestScheduler().runCurrent();
+ assertThat(mScrimBehind.getViewAlpha()).isEqualTo(expectedAlpha);
+ }
+
+ @Test
+ public void hubToLockscreenTransition_setsViewAlpha() {
+ // Start on glanceable hub.
+ mScrimController.transitionTo(ScrimState.GLANCEABLE_HUB);
+ finishAnimationsImmediately();
+
+ // Behind scrim starts at 0 alpha.
+ final float transitionProgress = 0f;
+ float expectedAlpha = 0f;
+ mKeyguardTransitionRepository.sendTransitionStepJava(mKosmos.getTestScope(),
+ new TransitionStep(
+ KeyguardState.GLANCEABLE_HUB,
+ KeyguardState.LOCKSCREEN,
+ transitionProgress,
+ TransitionState.STARTED
+ ), true);
+ mTestScope.getTestScheduler().runCurrent();
+ assertThat(mScrimBehind.getViewAlpha()).isEqualTo(expectedAlpha);
+
+ // Scrim fades in as transition runs.
+ final float runningProgress = 0.2f;
+ expectedAlpha = runningProgress * ScrimState.KEYGUARD.getBehindAlpha();
+ mKeyguardTransitionRepository.sendTransitionStepJava(mKosmos.getTestScope(),
+ new TransitionStep(
+ KeyguardState.GLANCEABLE_HUB,
+ KeyguardState.LOCKSCREEN,
+ runningProgress,
+ TransitionState.RUNNING
+ ), true);
+ mTestScope.getTestScheduler().runCurrent();
+ assertThat(mScrimBehind.getViewAlpha()).isEqualTo(expectedAlpha);
+
+ // Scrim at default visibility at end of transition.
+ final float finishedProgress = 1f;
+ expectedAlpha = finishedProgress * ScrimState.KEYGUARD.getBehindAlpha();
+ mKeyguardTransitionRepository.sendTransitionStepJava(mKosmos.getTestScope(),
+ new TransitionStep(
+ KeyguardState.GLANCEABLE_HUB,
+ KeyguardState.LOCKSCREEN,
+ finishedProgress,
+ TransitionState.FINISHED
+ ), true);
+ mTestScope.getTestScheduler().runCurrent();
+ assertThat(mScrimBehind.getViewAlpha()).isEqualTo(expectedAlpha);
+ }
+
+ @Test
+ public void transitionToHub() {
+ mScrimController.setRawPanelExpansionFraction(0f);
+ mScrimController.setBouncerHiddenFraction(KeyguardBouncerConstants.EXPANSION_HIDDEN);
+ mScrimController.transitionTo(ScrimState.GLANCEABLE_HUB);
+ finishAnimationsImmediately();
+
+ // All scrims transparent on the hub.
+ assertScrimAlpha(Map.of(
+ mScrimInFront, TRANSPARENT,
+ mNotificationsScrim, TRANSPARENT,
+ mScrimBehind, TRANSPARENT));
+ }
+
+ @Test
+ public void openBouncerOnHub() {
+ mScrimController.transitionTo(ScrimState.GLANCEABLE_HUB);
+
+ // Open the bouncer.
+ mScrimController.setRawPanelExpansionFraction(0f);
+ mScrimController.setBouncerHiddenFraction(KeyguardBouncerConstants.EXPANSION_VISIBLE);
+ finishAnimationsImmediately();
+
+ // Only behind widget is visible.
+ assertScrimAlpha(Map.of(
+ mScrimInFront, TRANSPARENT,
+ mNotificationsScrim, TRANSPARENT,
+ mScrimBehind, OPAQUE));
+
+ // Bouncer is closed.
+ mScrimController.setBouncerHiddenFraction(KeyguardBouncerConstants.EXPANSION_HIDDEN);
+ mScrimController.transitionTo(ScrimState.GLANCEABLE_HUB);
+ finishAnimationsImmediately();
+
+ // All scrims are transparent.
+ assertScrimAlpha(Map.of(
+ mScrimInFront, TRANSPARENT,
+ mNotificationsScrim, TRANSPARENT,
+ mScrimBehind, TRANSPARENT));
+ }
+
+ @Test
+ public void openShadeOnHub() {
+ mScrimController.transitionTo(ScrimState.GLANCEABLE_HUB);
+
+ // Open the shade.
+ mScrimController.transitionTo(SHADE_LOCKED);
+ mScrimController.setQsPosition(1f, 0);
+ finishAnimationsImmediately();
+
+ // Shade scrims are visible.
+ assertScrimAlpha(Map.of(
+ mNotificationsScrim, OPAQUE,
+ mScrimInFront, TRANSPARENT,
+ mScrimBehind, OPAQUE));
+
+ mScrimController.transitionTo(ScrimState.GLANCEABLE_HUB);
+ finishAnimationsImmediately();
+
+ // All scrims are transparent.
+ assertScrimAlpha(Map.of(
+ mScrimInFront, TRANSPARENT,
+ mNotificationsScrim, TRANSPARENT,
+ mScrimBehind, TRANSPARENT));
+ }
+
+ @Test
public void onThemeChange_bouncerBehindTint_isUpdatedToSurfaceColor() {
assertEquals(BOUNCER.getBehindTint(), 0x112233);
mSurfaceColor = 0x223344;
@@ -1000,7 +1164,7 @@
mKeyguardTransitionInteractor,
mKeyguardInteractor,
mWallpaperRepository,
- mMainDispatcher,
+ mKosmos.getTestDispatcher(),
mLinearLargeScreenShadeInterpolator);
mScrimController.start();
mScrimController.setScrimVisibleListener(visible -> mScrimVisibility = visible);
@@ -1266,7 +1430,7 @@
ScrimState.UNINITIALIZED, ScrimState.KEYGUARD, BOUNCER,
ScrimState.DREAMING, ScrimState.BOUNCER_SCRIMMED, ScrimState.BRIGHTNESS_MIRROR,
ScrimState.UNLOCKED, SHADE_LOCKED, ScrimState.AUTH_SCRIMMED,
- ScrimState.AUTH_SCRIMMED_SHADE));
+ ScrimState.AUTH_SCRIMMED_SHADE, ScrimState.GLANCEABLE_HUB));
for (ScrimState state : ScrimState.values()) {
if (!lowPowerModeStates.contains(state) && !regularStates.contains(state)) {
@@ -1683,6 +1847,26 @@
}
@Test
+ public void notificationBoundsTopGetsPassedToKeyguard() {
+ mScrimController.transitionTo(SHADE_LOCKED);
+ mScrimController.setQsPosition(1f, 0);
+ finishAnimationsImmediately();
+
+ mScrimController.setNotificationsBounds(0f, 100f, 0f, 0f);
+ verify(mKeyguardInteractor).setTopClippingBounds(eq(100));
+ }
+
+ @Test
+ public void notificationBoundsTopDoesNotGetPassedToKeyguardWhenNotifScrimIsNotVisible() {
+ mScrimController.setKeyguardOccluded(true);
+ mScrimController.transitionTo(ScrimState.KEYGUARD);
+ finishAnimationsImmediately();
+
+ mScrimController.setNotificationsBounds(0f, 100f, 0f, 0f);
+ verify(mKeyguardInteractor).setTopClippingBounds(eq(null));
+ }
+
+ @Test
public void transitionToDreaming() {
mScrimController.setRawPanelExpansionFraction(0f);
mScrimController.setBouncerHiddenFraction(KeyguardBouncerConstants.EXPANSION_HIDDEN);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/data/prod/DeviceBasedSatelliteRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/data/prod/DeviceBasedSatelliteRepositoryImplTest.kt
index 5b5819d..77e48bff 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/data/prod/DeviceBasedSatelliteRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/data/prod/DeviceBasedSatelliteRepositoryImplTest.kt
@@ -102,29 +102,6 @@
}
@Test
- fun satelliteManagerThrows_checkSupportDoesNotCrash() =
- testScope.runTest {
- whenever(satelliteManager.requestIsSatelliteSupported(any(), any()))
- .thenThrow(IllegalStateException())
-
- systemClock.setUptimeMillis(Process.getStartUptimeMillis() + MIN_UPTIME)
-
- underTest =
- DeviceBasedSatelliteRepositoryImpl(
- Optional.of(satelliteManager),
- dispatcher,
- testScope.backgroundScope,
- FakeLogBuffer.Factory.create(),
- systemClock,
- )
-
- runCurrent()
-
- // Creating the repo does not crash, and we consider the feature not to be supported
- assertThat(underTest.satelliteSupport.value).isEqualTo(SatelliteSupport.NotSupported)
- }
-
- @Test
fun connectionState_mapsFromSatelliteModemState() =
testScope.runTest {
setupDefaultRepo()
@@ -132,7 +109,7 @@
runCurrent()
val callback =
withArgCaptor<SatelliteModemStateCallback> {
- verify(satelliteManager).registerForSatelliteModemStateChanged(any(), capture())
+ verify(satelliteManager).registerForModemStateChanged(any(), capture())
}
// Mapping from modem state to SatelliteConnectionState is rote, just run all of the
@@ -207,7 +184,7 @@
null
}
.`when`(satelliteManager)
- .requestIsSatelliteCommunicationAllowedForCurrentLocation(
+ .requestIsCommunicationAllowedForCurrentLocation(
any(),
any<OutcomeReceiver<Boolean, SatelliteException>>()
)
@@ -230,7 +207,7 @@
null
}
.`when`(satelliteManager)
- .requestIsSatelliteCommunicationAllowedForCurrentLocation(
+ .requestIsCommunicationAllowedForCurrentLocation(
any(),
any<OutcomeReceiver<Boolean, SatelliteException>>()
)
@@ -253,7 +230,7 @@
null
}
.`when`(satelliteManager)
- .requestIsSatelliteCommunicationAllowedForCurrentLocation(
+ .requestIsCommunicationAllowedForCurrentLocation(
any(),
any<OutcomeReceiver<Boolean, SatelliteException>>()
)
@@ -297,7 +274,7 @@
null
}
.`when`(satelliteManager)
- .requestIsSatelliteCommunicationAllowedForCurrentLocation(
+ .requestIsCommunicationAllowedForCurrentLocation(
any(),
any<OutcomeReceiver<Boolean, SatelliteException>>()
)
@@ -330,7 +307,7 @@
null
}
.`when`(satelliteManager)
- .requestIsSatelliteCommunicationAllowedForCurrentLocation(
+ .requestIsCommunicationAllowedForCurrentLocation(
any(),
any<OutcomeReceiver<Boolean, SatelliteException>>()
)
@@ -356,7 +333,7 @@
val signalStrength by collectLastValue(underTest.signalStrength)
// THEN the manager is not asked for the information, and default values are returned
- verify(satelliteManager, never()).registerForSatelliteModemStateChanged(any(), any())
+ verify(satelliteManager, never()).registerForModemStateChanged(any(), any())
verify(satelliteManager, never()).registerForNtnSignalStrengthChanged(any(), any())
}
@@ -382,7 +359,7 @@
runCurrent()
// THEN we finally register with the satellite manager
- verify(satelliteManager).registerForSatelliteModemStateChanged(any(), any())
+ verify(satelliteManager).registerForModemStateChanged(any(), any())
}
private fun setUpRepo(
@@ -396,7 +373,7 @@
callback.onResult(satelliteSupported)
}
.whenever(satelliteManager)
- .requestIsSatelliteSupported(any(), any())
+ .requestIsSupported(any(), any())
systemClock.setUptimeMillis(Process.getStartUptimeMillis() + uptime)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractorTest.kt
index e010b86..d465b47 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractorTest.kt
@@ -16,6 +16,8 @@
package com.android.systemui.statusbar.pipeline.satellite.domain.interactor
+import android.platform.test.annotations.DisableFlags
+import android.platform.test.annotations.EnableFlags
import androidx.test.filters.SmallTest
import com.android.internal.telephony.flags.Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG
import com.android.systemui.SysuiTestCase
@@ -49,8 +51,6 @@
@Before
fun setUp() {
- mSetFlagsRule.enableFlags(FLAG_OEM_ENABLED_SATELLITE_FLAG)
-
underTest =
DeviceBasedSatelliteInteractor(
repo,
@@ -60,6 +60,7 @@
}
@Test
+ @EnableFlags(FLAG_OEM_ENABLED_SATELLITE_FLAG)
fun isSatelliteAllowed_falseWhenNotAllowed() =
testScope.runTest {
val latest by collectLastValue(underTest.isSatelliteAllowed)
@@ -72,6 +73,7 @@
}
@Test
+ @EnableFlags(FLAG_OEM_ENABLED_SATELLITE_FLAG)
fun isSatelliteAllowed_trueWhenAllowed() =
testScope.runTest {
val latest by collectLastValue(underTest.isSatelliteAllowed)
@@ -84,10 +86,10 @@
}
@Test
+ @DisableFlags(FLAG_OEM_ENABLED_SATELLITE_FLAG)
fun isSatelliteAllowed_offWhenFlagIsOff() =
testScope.runTest {
// GIVEN feature is disabled
- mSetFlagsRule.disableFlags(FLAG_OEM_ENABLED_SATELLITE_FLAG)
// Remake the interactor so the flag is read
underTest =
@@ -107,6 +109,7 @@
}
@Test
+ @EnableFlags(FLAG_OEM_ENABLED_SATELLITE_FLAG)
fun connectionState_matchesRepositoryValue() =
testScope.runTest {
val latest by collectLastValue(underTest.connectionState)
@@ -129,10 +132,10 @@
}
@Test
+ @DisableFlags(FLAG_OEM_ENABLED_SATELLITE_FLAG)
fun connectionState_offWhenFeatureIsDisabled() =
testScope.runTest {
// GIVEN the flag is disabled
- mSetFlagsRule.disableFlags(FLAG_OEM_ENABLED_SATELLITE_FLAG)
// Remake the interactor so the flag is read
underTest =
@@ -164,6 +167,7 @@
}
@Test
+ @EnableFlags(FLAG_OEM_ENABLED_SATELLITE_FLAG)
fun signalStrength_matchesRepo() =
testScope.runTest {
val latest by collectLastValue(underTest.signalStrength)
@@ -182,10 +186,10 @@
}
@Test
+ @DisableFlags(FLAG_OEM_ENABLED_SATELLITE_FLAG)
fun signalStrength_zeroWhenDisabled() =
testScope.runTest {
// GIVEN the flag is enabled
- mSetFlagsRule.disableFlags(FLAG_OEM_ENABLED_SATELLITE_FLAG)
// Remake the interactor so the flag is read
underTest =
@@ -212,6 +216,19 @@
}
@Test
+ @EnableFlags(FLAG_OEM_ENABLED_SATELLITE_FLAG)
+ fun areAllConnectionsOutOfService_noConnections_yes() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.areAllConnectionsOutOfService)
+
+ // GIVEN, 0 connections
+
+ // THEN the value is propagated to this interactor
+ assertThat(latest).isTrue()
+ }
+
+ @Test
+ @EnableFlags(FLAG_OEM_ENABLED_SATELLITE_FLAG)
fun areAllConnectionsOutOfService_twoConnectionsOos_yes() =
testScope.runTest {
val latest by collectLastValue(underTest.areAllConnectionsOutOfService)
@@ -229,6 +246,7 @@
}
@Test
+ @EnableFlags(FLAG_OEM_ENABLED_SATELLITE_FLAG)
fun areAllConnectionsOutOfService_oneConnectionOos_yes() =
testScope.runTest {
val latest by collectLastValue(underTest.areAllConnectionsOutOfService)
@@ -244,6 +262,7 @@
}
@Test
+ @EnableFlags(FLAG_OEM_ENABLED_SATELLITE_FLAG)
fun areAllConnectionsOutOfService_oneConnectionInService_no() =
testScope.runTest {
val latest by collectLastValue(underTest.areAllConnectionsOutOfService)
@@ -259,6 +278,7 @@
}
@Test
+ @EnableFlags(FLAG_OEM_ENABLED_SATELLITE_FLAG)
fun areAllConnectionsOutOfService_twoConnectionsOneInService_no() =
testScope.runTest {
val latest by collectLastValue(underTest.areAllConnectionsOutOfService)
@@ -276,6 +296,7 @@
}
@Test
+ @EnableFlags(FLAG_OEM_ENABLED_SATELLITE_FLAG)
fun areAllConnectionsOutOfService_twoConnectionsInService_no() =
testScope.runTest {
val latest by collectLastValue(underTest.areAllConnectionsOutOfService)
@@ -293,10 +314,10 @@
}
@Test
+ @DisableFlags(FLAG_OEM_ENABLED_SATELLITE_FLAG)
fun areAllConnectionsOutOfService_falseWhenFlagIsOff() =
testScope.runTest {
// GIVEN the flag is disabled
- mSetFlagsRule.disableFlags(FLAG_OEM_ENABLED_SATELLITE_FLAG)
// Remake the interactor so the flag is read
underTest =
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 98f3ede..7eba3f0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
@@ -548,7 +548,7 @@
mZenModeConfig.suppressedVisualEffects = 0;
when(mZenModeController.getConfig()).thenReturn(mZenModeConfig);
- mSysUiState = new SysUiState(mDisplayTracker);
+ mSysUiState = new SysUiState(mDisplayTracker, mKosmos.getSceneContainerPlugin());
mSysUiState.addCallback(sysUiFlags -> {
mSysUiStateBubblesManageMenuExpanded =
(sysUiFlags
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java b/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java
index af7f4c8..b62b3a2 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java
@@ -21,17 +21,25 @@
import static org.mockito.Mockito.when;
import android.app.Instrumentation;
+import android.content.Context;
+import android.content.res.Resources;
import android.os.Build;
import android.os.Handler;
+import android.os.HandlerExecutor;
import android.os.Looper;
import android.os.MessageQueue;
import android.os.ParcelFileDescriptor;
+import android.platform.test.annotations.DisabledOnRavenwood;
import android.platform.test.flag.junit.SetFlagsRule;
+import android.platform.test.ravenwood.RavenwoodClassRule;
+import android.platform.test.ravenwood.RavenwoodRule;
+import android.test.mock.MockContext;
import android.testing.DexmakerShareClassLoaderRule;
import android.testing.LeakCheck;
import android.testing.TestWithLooperRule;
import android.testing.TestableLooper;
import android.util.Log;
+import android.util.Singleton;
import androidx.annotation.NonNull;
import androidx.core.animation.AndroidXAnimatorIsolationRule;
@@ -44,17 +52,24 @@
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
+import org.junit.ClassRule;
import org.junit.Rule;
import org.mockito.Mockito;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Executor;
import java.util.concurrent.Future;
/**
* Base class that does System UI specific setup.
*/
+// NOTE: This @DisabledOnRavenwood annotation is inherited to all subclasses (unless overridden
+// via a more-specific @EnabledOnRavenwood annotation); this means that by default all
+// subclasses will be "ignored" when executed on the Ravenwood testing environment; more
+// background on Ravenwood is available at go/ravenwood-docs
+@DisabledOnRavenwood
public abstract class SysuiTestCase {
private static final String TAG = "SysuiTestCase";
@@ -66,6 +81,23 @@
public AndroidXAnimatorIsolationRule mAndroidXAnimatorIsolationRule =
new AndroidXAnimatorIsolationRule();
+ /**
+ * Rule that respects class-level annotations such as {@code @DisabledOnRavenwood} when tests
+ * are running on Ravenwood; on all other test environments this rule is a no-op passthrough.
+ */
+ @ClassRule(order = Integer.MIN_VALUE + 1)
+ public static final RavenwoodClassRule sRavenwood = new RavenwoodClassRule();
+
+ /**
+ * Rule that defines and prepares the Ravenwood environment when tests are running on
+ * Ravenwood; on all other test environments this rule is a no-op passthrough.
+ */
+ @Rule(order = Integer.MIN_VALUE + 1)
+ public final RavenwoodRule mRavenwood = new RavenwoodRule.Builder()
+ .setProcessApp()
+ .setProvideMainThread(true)
+ .build();
+
@Rule
public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(DEVICE_DEFAULT);
@@ -78,7 +110,7 @@
@NonNull
private SysuiTestableContext createTestableContext() {
SysuiTestableContext context = new SysuiTestableContext(
- InstrumentationRegistry.getContext(), getLeakCheck());
+ getTestableContextBase(), getLeakCheck());
if (isRobolectricTest()) {
// Manually associate a Display to context for Robolectric test. Similar to b/214297409
return context.createDefaultDisplayContext();
@@ -87,6 +119,43 @@
}
}
+ @NonNull
+ private Context getTestableContextBase() {
+ if (isRavenwoodTest()) {
+ // TODO(b/292141694): build out Ravenwood support for Context
+ // Ravenwood doesn't yet provide a Context, but many SysUI tests assume one exists;
+ // so here we construct just enough of a Context to be useful; this will be replaced
+ // as more of the Ravenwood environment is built out
+ return new MockContext() {
+ @Override
+ public void setTheme(int resid) {
+ // TODO(b/318393625): build out Ravenwood support for Resources
+ // until then, ignored as no-op
+ }
+
+ @Override
+ public Resources getResources() {
+ // TODO(b/318393625): build out Ravenwood support for Resources
+ return Mockito.mock(Resources.class);
+ }
+
+ private Singleton<Executor> mMainExecutor = new Singleton<>() {
+ @Override
+ protected Executor create() {
+ return new HandlerExecutor(new Handler(Looper.getMainLooper()));
+ }
+ };
+
+ @Override
+ public Executor getMainExecutor() {
+ return mMainExecutor.get();
+ }
+ };
+ } else {
+ return InstrumentationRegistry.getContext();
+ }
+ }
+
@Rule
public final DexmakerShareClassLoaderRule mDexmakerShareClassLoaderRule =
new DexmakerShareClassLoaderRule();
@@ -103,17 +172,22 @@
public void SysuiSetup() throws Exception {
mSysuiDependency = new SysuiTestDependency(mContext, shouldFailOnLeakedReceiver());
mDependency = mSysuiDependency.install();
- mRealInstrumentation = InstrumentationRegistry.getInstrumentation();
- Instrumentation inst = spy(mRealInstrumentation);
- when(inst.getContext()).thenAnswer(invocation -> {
- throw new RuntimeException(
- "SysUI Tests should use SysuiTestCase#getContext or SysuiTestCase#mContext");
- });
- when(inst.getTargetContext()).thenAnswer(invocation -> {
- throw new RuntimeException(
- "SysUI Tests should use SysuiTestCase#getContext or SysuiTestCase#mContext");
- });
- InstrumentationRegistry.registerInstance(inst, InstrumentationRegistry.getArguments());
+ // TODO(b/292141694): build out Ravenwood support for Instrumentation
+ // Ravenwood doesn't yet provide Instrumentation, so we sidestep this global configuration
+ // step; any tests that rely on it are already being excluded on Ravenwood
+ if (!isRavenwoodTest()) {
+ mRealInstrumentation = InstrumentationRegistry.getInstrumentation();
+ Instrumentation inst = spy(mRealInstrumentation);
+ when(inst.getContext()).thenAnswer(invocation -> {
+ throw new RuntimeException(
+ "Tests should use SysuiTestCase#getContext or SysuiTestCase#mContext");
+ });
+ when(inst.getTargetContext()).thenAnswer(invocation -> {
+ throw new RuntimeException(
+ "Tests should use SysuiTestCase#getContext or SysuiTestCase#mContext");
+ });
+ InstrumentationRegistry.registerInstance(inst, InstrumentationRegistry.getArguments());
+ }
}
protected boolean shouldFailOnLeakedReceiver() {
@@ -209,7 +283,11 @@
}
public static boolean isRobolectricTest() {
- return Build.FINGERPRINT.contains("robolectric");
+ return !isRavenwoodTest() && Build.FINGERPRINT.contains("robolectric");
+ }
+
+ public static boolean isRavenwoodTest() {
+ return RavenwoodRule.isOnRavenwood();
}
private static final void validateThread(Looper l) {
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestDependency.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestDependency.kt
index d89d7b0..364d3b2 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestDependency.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestDependency.kt
@@ -34,10 +34,16 @@
// is missing (constructing the actual one would throw).
// TODO(b/219008720): Remove this.
dependency.injectMockDependency(SystemUIDialogManager::class.java)
- dependency.injectTestDependency(
- DialogLaunchAnimator::class.java,
- fakeDialogLaunchAnimator()
- )
+
+ // TODO(b/292141694): build out Ravenwood support for UI animations
+ // Ravenwood doesn't yet provide UI animations, so we sidestep this global configuration
+ // step; any tests that rely on it are already being excluded under Ravenwood
+ if (!SysuiTestCase.isRavenwoodTest()) {
+ dependency.injectTestDependency(
+ DialogLaunchAnimator::class.java,
+ fakeDialogLaunchAnimator()
+ )
+ }
// Many tests end up creating a BroadcastDispatcher. Instead, give them a fake that will
// record receivers registered. They are not actually leaked as they are kept just as a weak
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorKosmos.kt
index 7c8a7c8..2bd104d 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/authentication/domain/interactor/AuthenticationInteractorKosmos.kt
@@ -19,12 +19,14 @@
import com.android.systemui.authentication.data.repository.authenticationRepository
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.applicationCoroutineScope
+import com.android.systemui.kosmos.testDispatcher
import com.android.systemui.user.domain.interactor.selectedUserInteractor
val Kosmos.authenticationInteractor by
Kosmos.Fixture {
AuthenticationInteractor(
applicationScope = applicationCoroutineScope,
+ backgroundDispatcher = testDispatcher,
repository = authenticationRepository,
selectedUserInteractor = selectedUserInteractor,
)
diff --git a/core/java/android/credentials/ui/UiResult.java b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/UdfpsUtilsKosmos.kt
similarity index 75%
rename from core/java/android/credentials/ui/UiResult.java
rename to packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/UdfpsUtilsKosmos.kt
index 692584d..4849fec 100644
--- a/core/java/android/credentials/ui/UiResult.java
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/UdfpsUtilsKosmos.kt
@@ -14,11 +14,9 @@
* limitations under the License.
*/
-package android.credentials.ui;
+package com.android.systemui.biometrics
-/**
- * Base class for different types of ui results.
- *
- * @hide
- */
-public interface UiResult {}
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.util.mockito.mock
+
+var Kosmos.udfpsUtils by Kosmos.Fixture { mock<UdfpsUtils>() }
diff --git a/core/java/android/credentials/ui/UiResult.java b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/BiometricStatusRepositoryKosmos.kt
similarity index 72%
copy from core/java/android/credentials/ui/UiResult.java
copy to packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/BiometricStatusRepositoryKosmos.kt
index 692584d..961022f 100644
--- a/core/java/android/credentials/ui/UiResult.java
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/BiometricStatusRepositoryKosmos.kt
@@ -12,13 +12,12 @@
* WITHOUT WARRANTIES 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.credentials.ui;
-
-/**
- * Base class for different types of ui results.
*
- * @hide
*/
-public interface UiResult {}
+
+package com.android.systemui.biometrics.data.repository
+
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+
+val Kosmos.biometricStatusRepository by Fixture { FakeBiometricStatusRepository() }
diff --git a/core/java/android/credentials/ui/UiResult.java b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/PromptRepositoryKosmos.kt
similarity index 73%
copy from core/java/android/credentials/ui/UiResult.java
copy to packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/PromptRepositoryKosmos.kt
index 692584d..31fa5d2 100644
--- a/core/java/android/credentials/ui/UiResult.java
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/PromptRepositoryKosmos.kt
@@ -14,11 +14,9 @@
* limitations under the License.
*/
-package android.credentials.ui;
+package com.android.systemui.biometrics.data.repository
-/**
- * Base class for different types of ui results.
- *
- * @hide
- */
-public interface UiResult {}
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+
+var Kosmos.promptRepository by Fixture { FakePromptRepository() }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/domain/interactor/BiometricStatusInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/domain/interactor/BiometricStatusInteractorKosmos.kt
new file mode 100644
index 0000000..1493f14
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/domain/interactor/BiometricStatusInteractorKosmos.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.biometrics.domain.interactor
+
+import com.android.app.activityTaskManager
+import com.android.systemui.biometrics.data.repository.biometricStatusRepository
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+
+val Kosmos.biometricStatusInteractor by Fixture {
+ BiometricStatusInteractorImpl(
+ activityTaskManager = activityTaskManager,
+ biometricStatusRepository = biometricStatusRepository
+ )
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractorKosmos.kt
new file mode 100644
index 0000000..7f9a71c
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractorKosmos.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.biometrics.domain.interactor
+
+import com.android.internal.widget.lockPatternUtils
+import com.android.systemui.biometrics.data.repository.fingerprintPropertyRepository
+import com.android.systemui.biometrics.data.repository.promptRepository
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+
+val Kosmos.promptSelectorInteractor by Fixture {
+ PromptSelectorInteractorImpl(
+ fingerprintPropertyRepository = fingerprintPropertyRepository,
+ promptRepository = promptRepository,
+ lockPatternUtils = lockPatternUtils
+ )
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelKosmos.kt
new file mode 100644
index 0000000..9cbe633
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelKosmos.kt
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.biometrics.ui.viewmodel
+
+import android.content.applicationContext
+import com.android.systemui.biometrics.domain.interactor.displayStateInteractor
+import com.android.systemui.biometrics.domain.interactor.promptSelectorInteractor
+import com.android.systemui.biometrics.domain.interactor.udfpsOverlayInteractor
+import com.android.systemui.biometrics.udfpsUtils
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+
+val Kosmos.promptViewModel by Fixture {
+ PromptViewModel(
+ displayStateInteractor = displayStateInteractor,
+ promptSelectorInteractor = promptSelectorInteractor,
+ context = applicationContext,
+ udfpsOverlayInteractor = udfpsOverlayInteractor,
+ udfpsUtils = udfpsUtils
+ )
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalInteractorKosmos.kt
index 1abf71f..c818e9c 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalInteractorKosmos.kt
@@ -24,14 +24,12 @@
import com.android.systemui.keyguard.domain.interactor.keyguardInteractor
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.Kosmos.Fixture
-import com.android.systemui.kosmos.applicationCoroutineScope
import com.android.systemui.smartspace.data.repository.smartspaceRepository
import com.android.systemui.user.data.repository.userRepository
import com.android.systemui.util.mockito.mock
val Kosmos.communalInteractor by Fixture {
CommunalInteractor(
- applicationScope = applicationCoroutineScope,
communalRepository = communalRepository,
widgetRepository = communalWidgetRepository,
mediaRepository = communalMediaRepository,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardTransitionRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardTransitionRepository.kt
index 0c1dbfe..e20a0ab 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardTransitionRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardTransitionRepository.kt
@@ -28,9 +28,12 @@
import java.util.UUID
import javax.inject.Inject
import junit.framework.Assert.fail
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Job
import kotlinx.coroutines.channels.BufferOverflow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.SharedFlow
+import kotlinx.coroutines.launch
import kotlinx.coroutines.test.TestCoroutineScheduler
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent
@@ -150,6 +153,15 @@
_transitions.emit(step)
}
+ /** Version of [sendTransitionStep] that's usable from Java tests. */
+ fun sendTransitionStepJava(
+ coroutineScope: CoroutineScope,
+ step: TransitionStep,
+ validateStep: Boolean = true
+ ): Job {
+ return coroutineScope.launch { sendTransitionStep(step, validateStep) }
+ }
+
suspend fun sendTransitionSteps(
steps: List<TransitionStep>,
testScope: TestScope,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt
index 321f944..083de10 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt
@@ -32,6 +32,9 @@
import com.android.systemui.flags.fakeFeatureFlagsClassic
import com.android.systemui.jank.interactionJankMonitor
import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
+import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor
+import com.android.systemui.model.sceneContainerPlugin
import com.android.systemui.plugins.statusbar.statusBarStateController
import com.android.systemui.power.data.repository.fakePowerRepository
import com.android.systemui.power.domain.interactor.powerInteractor
@@ -60,6 +63,8 @@
val bouncerRepository by lazy { kosmos.bouncerRepository }
val communalRepository by lazy { kosmos.fakeCommunalRepository }
val keyguardRepository by lazy { kosmos.fakeKeyguardRepository }
+ val keyguardTransitionRepository by lazy { kosmos.fakeKeyguardTransitionRepository }
+ val keyguardTransitionInteractor by lazy { kosmos.keyguardTransitionInteractor }
val powerRepository by lazy { kosmos.fakePowerRepository }
val clock by lazy { kosmos.systemClock }
val mobileConnectionsRepository by lazy { kosmos.fakeMobileConnectionsRepository }
@@ -74,6 +79,7 @@
val deviceEntryInteractor by lazy { kosmos.deviceEntryInteractor }
val deviceUnlockedInteractor by lazy { kosmos.deviceUnlockedInteractor }
val communalInteractor by lazy { kosmos.communalInteractor }
+ val sceneContainerPlugin by lazy { kosmos.sceneContainerPlugin }
init {
kosmos.applicationContext = testCase.context
diff --git a/core/java/android/credentials/ui/UiResult.java b/packages/SystemUI/tests/utils/src/com/android/systemui/model/SceneContainerPluginKosmos.kt
similarity index 67%
copy from core/java/android/credentials/ui/UiResult.java
copy to packages/SystemUI/tests/utils/src/com/android/systemui/model/SceneContainerPluginKosmos.kt
index 692584d..b1027b9 100644
--- a/core/java/android/credentials/ui/UiResult.java
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/model/SceneContainerPluginKosmos.kt
@@ -14,11 +14,10 @@
* limitations under the License.
*/
-package android.credentials.ui;
+package com.android.systemui.model
-/**
- * Base class for different types of ui results.
- *
- * @hide
- */
-public interface UiResult {}
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.scene.domain.interactor.sceneInteractor
+
+val Kosmos.sceneContainerPlugin by Fixture { SceneContainerPlugin { sceneInteractor } }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeAnimationInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeAnimationInteractorKosmos.kt
index 57b272f..d2dd200 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeAnimationInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeAnimationInteractorKosmos.kt
@@ -17,7 +17,12 @@
package com.android.systemui.shade.domain.interactor
import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.scene.domain.interactor.sceneInteractor
import com.android.systemui.shade.data.repository.shadeAnimationRepository
var Kosmos.shadeAnimationInteractor: ShadeAnimationInteractor by
Kosmos.Fixture { ShadeAnimationInteractorEmptyImpl(shadeAnimationRepository) }
+var Kosmos.shadeAnimationInteractorSceneContainerImpl: ShadeAnimationInteractorSceneContainerImpl by
+ Kosmos.Fixture {
+ ShadeAnimationInteractorSceneContainerImpl(shadeAnimationRepository, sceneInteractor)
+ }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/ConfigurationControllerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/ConfigurationControllerKosmos.kt
index 18a2f94..33ed7e6 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/ConfigurationControllerKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/ConfigurationControllerKosmos.kt
@@ -20,3 +20,5 @@
import com.android.systemui.util.mockito.mock
val Kosmos.configurationController by Kosmos.Fixture { mock<ConfigurationController>() }
+val Kosmos.fakeConfigurationController: FakeConfigurationController by
+ Kosmos.Fixture { FakeConfigurationController() }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/VolumePanelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/VolumePanelKosmos.kt
new file mode 100644
index 0000000..d341073
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/VolumePanelKosmos.kt
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.volume.panel
+
+import android.content.res.mainResources
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.statusbar.policy.fakeConfigurationController
+import com.android.systemui.util.mockito.mock
+import com.android.systemui.volume.panel.dagger.factory.KosmosVolumePanelComponentFactory
+import com.android.systemui.volume.panel.domain.ComponentAvailabilityCriteria
+import com.android.systemui.volume.panel.domain.TestComponentAvailabilityCriteria
+import com.android.systemui.volume.panel.domain.interactor.ComponentsInteractor
+import com.android.systemui.volume.panel.domain.interactor.ComponentsInteractorImpl
+import com.android.systemui.volume.panel.shared.model.VolumePanelComponentKey
+import com.android.systemui.volume.panel.shared.model.VolumePanelUiComponent
+import com.android.systemui.volume.panel.ui.composable.ComponentsFactory
+import com.android.systemui.volume.panel.ui.layout.ComponentsLayoutManager
+import com.android.systemui.volume.panel.ui.viewmodel.VolumePanelViewModel
+import javax.inject.Provider
+
+val Kosmos.mockVolumePanelUiComponent: VolumePanelUiComponent by Kosmos.Fixture { mock {} }
+val Kosmos.mockVolumePanelUiComponentProvider: Provider<VolumePanelUiComponent> by
+ Kosmos.Fixture { Provider { mockVolumePanelUiComponent } }
+var Kosmos.componentByKey: Map<VolumePanelComponentKey, Provider<VolumePanelUiComponent>> by
+ Kosmos.Fixture { emptyMap() }
+val Kosmos.componentsFactory: ComponentsFactory by
+ Kosmos.Fixture { ComponentsFactory(componentByKey) }
+
+var Kosmos.componentsLayoutManager: ComponentsLayoutManager by Kosmos.Fixture()
+var Kosmos.enabledComponents: Collection<VolumePanelComponentKey> by
+ Kosmos.Fixture { componentByKey.keys }
+val Kosmos.unavailableCriteria: Provider<ComponentAvailabilityCriteria> by
+ Kosmos.Fixture { Provider { TestComponentAvailabilityCriteria(false) } }
+val Kosmos.availableCriteria: Provider<ComponentAvailabilityCriteria> by
+ Kosmos.Fixture { Provider { TestComponentAvailabilityCriteria(true) } }
+var Kosmos.defaultCriteria: Provider<ComponentAvailabilityCriteria> by
+ Kosmos.Fixture { availableCriteria }
+var Kosmos.criteriaByKey: Map<VolumePanelComponentKey, Provider<ComponentAvailabilityCriteria>> by
+ Kosmos.Fixture { emptyMap() }
+var Kosmos.componentsInteractor: ComponentsInteractor by
+ Kosmos.Fixture {
+ ComponentsInteractorImpl(
+ enabledComponents,
+ defaultCriteria,
+ testScope.backgroundScope,
+ criteriaByKey,
+ )
+ }
+
+var Kosmos.volumePanelViewModel: VolumePanelViewModel by
+ Kosmos.Fixture {
+ VolumePanelViewModel(
+ mainResources,
+ KosmosVolumePanelComponentFactory(this),
+ fakeConfigurationController,
+ )
+ }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/dagger/factory/KosmosVolumePanelComponentFactory.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/dagger/factory/KosmosVolumePanelComponentFactory.kt
new file mode 100644
index 0000000..49041ed
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/dagger/factory/KosmosVolumePanelComponentFactory.kt
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.volume.panel.dagger.factory
+
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.volume.panel.componentsFactory
+import com.android.systemui.volume.panel.componentsInteractor
+import com.android.systemui.volume.panel.componentsLayoutManager
+import com.android.systemui.volume.panel.dagger.VolumePanelComponent
+import com.android.systemui.volume.panel.domain.interactor.ComponentsInteractor
+import com.android.systemui.volume.panel.ui.composable.ComponentsFactory
+import com.android.systemui.volume.panel.ui.layout.ComponentsLayoutManager
+import com.android.systemui.volume.panel.ui.viewmodel.VolumePanelViewModel
+import kotlinx.coroutines.CoroutineScope
+
+class KosmosVolumePanelComponentFactory(private val kosmos: Kosmos) : VolumePanelComponentFactory {
+
+ override fun create(viewModel: VolumePanelViewModel): VolumePanelComponent =
+ object : VolumePanelComponent {
+
+ override fun coroutineScope(): CoroutineScope = kosmos.testScope.backgroundScope
+
+ override fun componentsInteractor(): ComponentsInteractor = kosmos.componentsInteractor
+
+ override fun componentsFactory(): ComponentsFactory = kosmos.componentsFactory
+
+ override fun componentsLayoutManager(): ComponentsLayoutManager =
+ kosmos.componentsLayoutManager
+ }
+}
diff --git a/core/java/android/credentials/ui/UiResult.java b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/domain/TestComponentAvailabilityCriteria.kt
similarity index 67%
copy from core/java/android/credentials/ui/UiResult.java
copy to packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/domain/TestComponentAvailabilityCriteria.kt
index 692584d..5ab9274 100644
--- a/core/java/android/credentials/ui/UiResult.java
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/domain/TestComponentAvailabilityCriteria.kt
@@ -14,11 +14,12 @@
* limitations under the License.
*/
-package android.credentials.ui;
+package com.android.systemui.volume.panel.domain
-/**
- * Base class for different types of ui results.
- *
- * @hide
- */
-public interface UiResult {}
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.flowOf
+
+class TestComponentAvailabilityCriteria(val isAvailable: Boolean) : ComponentAvailabilityCriteria {
+
+ override fun isAvailable(): Flow<Boolean> = flowOf(isAvailable)
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/ui/layout/FakeComponentsLayoutManager.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/ui/layout/FakeComponentsLayoutManager.kt
new file mode 100644
index 0000000..655d8f7
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/ui/layout/FakeComponentsLayoutManager.kt
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.volume.panel.ui.layout
+
+import com.android.systemui.volume.panel.ui.viewmodel.ComponentState
+import com.android.systemui.volume.panel.ui.viewmodel.VolumePanelState
+
+class FakeComponentsLayoutManager(
+ private val isBottomBar: (components: ComponentState) -> Boolean
+) : ComponentsLayoutManager {
+
+ override fun layout(
+ volumePanelState: VolumePanelState,
+ components: Collection<ComponentState>
+ ): ComponentsLayout {
+ return ComponentsLayout(
+ components
+ .filter { componentState -> !isBottomBar(componentState) }
+ .sortedBy { it.key },
+ components.find(isBottomBar)!!,
+ )
+ }
+}
diff --git a/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java b/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java
index 3aa9cc8..155c523 100644
--- a/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java
+++ b/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java
@@ -132,7 +132,7 @@
private static final String CAMERA_EXTENSION_VERSION_NAME =
"androidx.camera.extensions.impl.ExtensionVersionImpl";
- private static final String LATEST_VERSION = "1.4.0";
+ private static final String LATEST_VERSION = "1.5.0";
// No support for the init sequence
private static final String NON_INIT_VERSION_PREFIX = "1.0";
// Support advanced API and latency queries
@@ -1693,6 +1693,7 @@
private final Size mSize;
private final int mImageFormat;
private final int mDataspace;
+ private final long mUsage;
public OutputSurfaceImplStub(OutputSurface outputSurface) {
mSurface = outputSurface.surface;
@@ -1700,8 +1701,10 @@
mImageFormat = outputSurface.imageFormat;
if (mSurface != null) {
mDataspace = SurfaceUtils.getSurfaceDataspace(mSurface);
+ mUsage = SurfaceUtils.getSurfaceUsage(mSurface);
} else {
mDataspace = -1;
+ mUsage = 0;
}
}
@@ -1724,6 +1727,11 @@
public int getDataspace() {
return mDataspace;
}
+
+ @Override
+ public long getUsage() {
+ return mUsage;
+ }
}
private class PreviewExtenderImplStub extends IPreviewExtenderImpl.Stub implements
@@ -2471,6 +2479,11 @@
ret.size.height = imageReaderOutputConfig.getSize().getHeight();
ret.imageFormat = imageReaderOutputConfig.getImageFormat();
ret.capacity = imageReaderOutputConfig.getMaxImages();
+ if (EFV_SUPPORTED) {
+ ret.usage = imageReaderOutputConfig.getUsage();
+ } else {
+ ret.usage = 0;
+ }
} else if (output instanceof MultiResolutionImageReaderOutputConfigImpl) {
MultiResolutionImageReaderOutputConfigImpl multiResReaderConfig =
(MultiResolutionImageReaderOutputConfigImpl) output;
diff --git a/ravenwood/Android.bp b/ravenwood/Android.bp
index e013a3e..1ac69f6 100644
--- a/ravenwood/Android.bp
+++ b/ravenwood/Android.bp
@@ -30,6 +30,9 @@
"junit-src/**/*.java",
"junit-impl-src/**/*.java",
],
+ static_libs: [
+ "androidx.test.monitor-for-device",
+ ],
libs: [
"framework-minus-apex.ravenwood",
"junit",
@@ -61,3 +64,17 @@
"core-xml-for-host",
],
}
+
+java_host_for_device {
+ name: "androidx.test.monitor-for-device",
+ libs: [
+ "androidx.test.monitor-for-host",
+ ],
+}
+
+java_device_for_host {
+ name: "androidx.test.monitor-for-host",
+ libs: [
+ "androidx.test.monitor",
+ ],
+}
diff --git a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java
index 91c522e..a797b1d 100644
--- a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java
+++ b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java
@@ -16,13 +16,36 @@
package android.platform.test.ravenwood;
+import android.app.Instrumentation;
+import android.os.Bundle;
import android.os.HandlerThread;
import android.os.Looper;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import java.io.PrintStream;
+import java.util.Map;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+
public class RavenwoodRuleImpl {
private static final String MAIN_THREAD_NAME = "RavenwoodMain";
- public static boolean isUnderRavenwood() {
+ /**
+ * When enabled, attempt to dump all thread stacks just before we hit the
+ * overall Tradefed timeout, to aid in debugging deadlocks.
+ */
+ private static final boolean ENABLE_TIMEOUT_STACKS = false;
+ private static final int TIMEOUT_MILLIS = 9_000;
+
+ private static final ScheduledExecutorService sTimeoutExecutor =
+ Executors.newScheduledThreadPool(1);
+
+ private static ScheduledFuture<?> sPendingTimeout;
+
+ public static boolean isOnRavenwood() {
return true;
}
@@ -41,9 +64,22 @@
main.start();
Looper.setMainLooperForTest(main.getLooper());
}
+
+ InstrumentationRegistry.registerInstance(new Instrumentation(), Bundle.EMPTY);
+
+ if (ENABLE_TIMEOUT_STACKS) {
+ sPendingTimeout = sTimeoutExecutor.schedule(RavenwoodRuleImpl::dumpStacks,
+ TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
+ }
}
public static void reset(RavenwoodRule rule) {
+ if (ENABLE_TIMEOUT_STACKS) {
+ sPendingTimeout.cancel(false);
+ }
+
+ InstrumentationRegistry.registerInstance(null, Bundle.EMPTY);
+
if (rule.mProvideMainThread) {
Looper.getMainLooper().quit();
Looper.clearMainLooperForTest();
@@ -55,4 +91,19 @@
android.os.Binder.reset$ravenwood();
android.os.Process.reset$ravenwood();
}
+
+ private static void dumpStacks() {
+ final PrintStream out = System.err;
+ out.println("-----BEGIN ALL THREAD STACKS-----");
+ final Map<Thread, StackTraceElement[]> stacks = Thread.getAllStackTraces();
+ for (Map.Entry<Thread, StackTraceElement[]> stack : stacks.entrySet()) {
+ out.println();
+ Thread t = stack.getKey();
+ out.println(t.toString() + " ID=" + t.getId());
+ for (StackTraceElement e : stack.getValue()) {
+ out.println("\tat " + e);
+ }
+ }
+ out.println("-----END ALL THREAD STACKS-----");
+ }
}
diff --git a/ravenwood/junit-src/android/platform/test/annotations/IncludeUnderRavenwood.java b/ravenwood/junit-src/android/platform/test/annotations/DisabledOnRavenwood.java
similarity index 74%
rename from ravenwood/junit-src/android/platform/test/annotations/IncludeUnderRavenwood.java
rename to ravenwood/junit-src/android/platform/test/annotations/DisabledOnRavenwood.java
index 0b2e32f..4bf0980 100644
--- a/ravenwood/junit-src/android/platform/test/annotations/IncludeUnderRavenwood.java
+++ b/ravenwood/junit-src/android/platform/test/annotations/DisabledOnRavenwood.java
@@ -23,15 +23,16 @@
import java.lang.annotation.Target;
/**
- * Tests marked with this annotation are included when running under a Ravenwood test environment.
+ * Tests marked with this annotation are disabled when running under a Ravenwood test environment.
*
* A more specific method-level annotation always takes precedence over any class-level
- * annotation, and an {@link IncludeUnderRavenwood} annotation always takes precedence over
- * an {@link ExcludeUnderRavenwood} annotation.
+ * annotation, and an {@link EnabledOnRavenwood} annotation always takes precedence over
+ * an {@link DisabledOnRavenwood} annotation.
*
* This annotation only takes effect when the containing class has a {@code
- * RavenwoodRule} configured. Ignoring is accomplished by throwing an {@code org.junit
- * .AssumptionViolatedException} which test infrastructure treats as being ignored.
+ * RavenwoodRule} or {@code RavenwoodClassRule} configured. Ignoring is accomplished by
+ * throwing an {@code org.junit.AssumptionViolatedException} which test infrastructure treats as
+ * being ignored.
*
* This annotation has no effect on any other non-Ravenwood test environments.
*
@@ -40,5 +41,5 @@
@Inherited
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
-public @interface IncludeUnderRavenwood {
+public @interface DisabledOnRavenwood {
}
diff --git a/ravenwood/junit-src/android/platform/test/annotations/IncludeUnderRavenwood.java b/ravenwood/junit-src/android/platform/test/annotations/EnabledOnRavenwood.java
similarity index 72%
copy from ravenwood/junit-src/android/platform/test/annotations/IncludeUnderRavenwood.java
copy to ravenwood/junit-src/android/platform/test/annotations/EnabledOnRavenwood.java
index 0b2e32f..9dd0a58 100644
--- a/ravenwood/junit-src/android/platform/test/annotations/IncludeUnderRavenwood.java
+++ b/ravenwood/junit-src/android/platform/test/annotations/EnabledOnRavenwood.java
@@ -23,15 +23,16 @@
import java.lang.annotation.Target;
/**
- * Tests marked with this annotation are included when running under a Ravenwood test environment.
+ * Tests marked with this annotation are enabled when running under a Ravenwood test environment.
*
* A more specific method-level annotation always takes precedence over any class-level
- * annotation, and an {@link IncludeUnderRavenwood} annotation always takes precedence over
- * an {@link ExcludeUnderRavenwood} annotation.
+ * annotation, and an {@link EnabledOnRavenwood} annotation always takes precedence over
+ * an {@link DisabledOnRavenwood} annotation.
*
* This annotation only takes effect when the containing class has a {@code
- * RavenwoodRule} configured. Ignoring is accomplished by throwing an {@code org.junit
- * .AssumptionViolatedException} which test infrastructure treats as being ignored.
+ * RavenwoodRule} or {@code RavenwoodClassRule} configured. Ignoring is accomplished by
+ * throwing an {@code org.junit.AssumptionViolatedException} which test infrastructure treats as
+ * being ignored.
*
* This annotation has no effect on any other non-Ravenwood test environments.
*
@@ -40,5 +41,5 @@
@Inherited
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
-public @interface IncludeUnderRavenwood {
+public @interface EnabledOnRavenwood {
}
diff --git a/ravenwood/junit-src/android/platform/test/annotations/ExcludeUnderRavenwood.java b/ravenwood/junit-src/android/platform/test/annotations/ExcludeUnderRavenwood.java
deleted file mode 100644
index 2ef381e..0000000
--- a/ravenwood/junit-src/android/platform/test/annotations/ExcludeUnderRavenwood.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.platform.test.annotations;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Inherited;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-/**
- * Tests marked with this annotation are excluded when running under a Ravenwood test environment.
- *
- * A more specific method-level annotation always takes precedence over any class-level
- * annotation, and an {@link IncludeUnderRavenwood} annotation always takes precedence over
- * an {@link ExcludeUnderRavenwood} annotation.
- *
- * This annotation only takes effect when the containing class has a {@code
- * RavenwoodRule} configured. Ignoring is accomplished by throwing an {@code org.junit
- * .AssumptionViolatedException} which test infrastructure treats as being ignored.
- *
- * This annotation has no effect on any other non-Ravenwood test environments.
- *
- * @hide
- */
-@Inherited
-@Target({ElementType.METHOD, ElementType.TYPE})
-@Retention(RetentionPolicy.RUNTIME)
-public @interface ExcludeUnderRavenwood {
-}
diff --git a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodClassRule.java b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodClassRule.java
new file mode 100644
index 0000000..8d76970
--- /dev/null
+++ b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodClassRule.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.platform.test.ravenwood;
+
+import static android.platform.test.ravenwood.RavenwoodRule.ENABLE_PROBE_IGNORED;
+import static android.platform.test.ravenwood.RavenwoodRule.IS_ON_RAVENWOOD;
+import static android.platform.test.ravenwood.RavenwoodRule.shouldEnableOnRavenwood;
+import static android.platform.test.ravenwood.RavenwoodRule.shouldStillIgnoreInProbeIgnoreMode;
+
+import android.platform.test.annotations.DisabledOnRavenwood;
+import android.platform.test.annotations.EnabledOnRavenwood;
+
+import org.junit.Assume;
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+/**
+ * {@code @ClassRule} that respects Ravenwood-specific class annotations. This rule has no effect
+ * when tests are run on non-Ravenwood test environments.
+ *
+ * By default, all tests are executed on Ravenwood, but annotations such as
+ * {@link DisabledOnRavenwood} and {@link EnabledOnRavenwood} can be used at both the method
+ * and class level to "ignore" tests that may not be ready.
+ */
+public class RavenwoodClassRule implements TestRule {
+ @Override
+ public Statement apply(Statement base, Description description) {
+ // No special treatment when running outside Ravenwood; run tests as-is
+ if (!IS_ON_RAVENWOOD) {
+ return base;
+ }
+
+ if (ENABLE_PROBE_IGNORED) {
+ Assume.assumeFalse(shouldStillIgnoreInProbeIgnoreMode(description));
+ // Pass through to possible underlying RavenwoodRule for both environment
+ // configuration and handling method-level annotations
+ return base;
+ } else {
+ return new Statement() {
+ @Override
+ public void evaluate() throws Throwable {
+ Assume.assumeTrue(shouldEnableOnRavenwood(description));
+ // Pass through to possible underlying RavenwoodRule for both environment
+ // configuration and handling method-level annotations
+ base.evaluate();
+ }
+ };
+ }
+ }
+}
diff --git a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java
index dd442f0..1e7cbf6 100644
--- a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java
+++ b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java
@@ -18,41 +18,88 @@
import static org.junit.Assert.fail;
-import android.platform.test.annotations.ExcludeUnderRavenwood;
+import android.platform.test.annotations.DisabledOnRavenwood;
+import android.platform.test.annotations.EnabledOnRavenwood;
import android.platform.test.annotations.IgnoreUnderRavenwood;
-import android.platform.test.annotations.IncludeUnderRavenwood;
import org.junit.Assume;
import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
+import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger;
+import java.util.regex.Pattern;
/**
- * THIS RULE IS EXPERIMENTAL. REACH OUT TO g/ravenwood BEFORE USING IT, OR YOU HAVE ANY
- * QUESTIONS ABOUT IT.
+ * {@code @Rule} that configures the Ravenwood test environment. This rule has no effect when
+ * tests are run on non-Ravenwood test environments.
*
- * @hide
+ * This rule initializes and resets the Ravenwood environment between each test method to offer a
+ * hermetic testing environment.
+ *
+ * By default, all tests are executed on Ravenwood, but annotations such as
+ * {@link DisabledOnRavenwood} and {@link EnabledOnRavenwood} can be used at both the method
+ * and class level to "ignore" tests that may not be ready. When needed, a
+ * {@link RavenwoodClassRule} can be used in addition to a {@link RavenwoodRule} to ignore tests
+ * before a test class is fully initialized.
*/
public class RavenwoodRule implements TestRule {
- private static AtomicInteger sNextPid = new AtomicInteger(100);
-
- private static final boolean IS_UNDER_RAVENWOOD = RavenwoodRuleImpl.isUnderRavenwood();
+ static final boolean IS_ON_RAVENWOOD = RavenwoodRuleImpl.isOnRavenwood();
/**
- * When probing is enabled, all tests will be unconditionally run under Ravenwood to detect
+ * When probing is enabled, all tests will be unconditionally run on Ravenwood to detect
* cases where a test is able to pass despite being marked as {@code IgnoreUnderRavenwood}.
*
* This is typically helpful for internal maintainers discovering tests that had previously
* been ignored, but now have enough Ravenwood-supported functionality to be enabled.
*/
- private static final boolean ENABLE_PROBE_IGNORED = false; // DO NOT SUBMIT WITH TRUE
+ static final boolean ENABLE_PROBE_IGNORED = "1".equals(
+ System.getenv("RAVENWOOD_RUN_DISABLED_TESTS"));
+
+ /**
+ * When using ENABLE_PROBE_IGNORED, you may still want to skip certain tests,
+ * for example because the test would crash the JVM.
+ *
+ * This regex defines the tests that should still be disabled even if ENABLE_PROBE_IGNORED
+ * is set.
+ *
+ * Before running each test class and method, we check if this pattern can be found in
+ * the full test name (either [class full name], or [class full name] + "#" + [method name]),
+ * and if so, we skip it.
+ *
+ * For example, if you want to skip an entire test class, use:
+ * RAVENWOOD_REALLY_DISABLE='\.CustomTileDefaultsRepositoryTest$'
+ *
+ * For example, if you want to skip an entire test class, use:
+ * RAVENWOOD_REALLY_DISABLE='\.CustomTileDefaultsRepositoryTest#testSimple$'
+ *
+ * To ignore multiple classes, use (...|...), for example:
+ * RAVENWOOD_REALLY_DISABLE='\.(ClassA|ClassB)$'
+ *
+ * Because we use a regex-find, setting "." would disable all tests.
+ */
+ private static final Pattern REALLY_DISABLE_PATTERN = Pattern.compile(
+ Objects.requireNonNullElse(System.getenv("RAVENWOOD_REALLY_DISABLE"), ""));
+
+ private static final boolean ENABLE_REALLY_DISABLE_PATTERN =
+ !REALLY_DISABLE_PATTERN.pattern().isEmpty();
+
+ static {
+ if (ENABLE_PROBE_IGNORED) {
+ System.out.println("$RAVENWOOD_RUN_DISABLED_TESTS enabled: force running all tests");
+ if (ENABLE_REALLY_DISABLE_PATTERN) {
+ System.out.println("$RAVENWOOD_REALLY_DISABLE=" + REALLY_DISABLE_PATTERN.pattern());
+ }
+ }
+ }
private static final int SYSTEM_UID = 1000;
private static final int NOBODY_UID = 9999;
private static final int FIRST_APPLICATION_UID = 10000;
+ private static final AtomicInteger sNextPid = new AtomicInteger(100);
+
/**
* Unless the test author requests differently, run as "nobody", and give each collection of
* tests its own unique PID.
@@ -75,7 +122,7 @@
/**
* Configure the identity of this process to be the system UID for the duration of the
- * test. Has no effect under non-Ravenwood environments.
+ * test. Has no effect on non-Ravenwood environments.
*/
public Builder setProcessSystem() {
mRule.mUid = SYSTEM_UID;
@@ -84,7 +131,7 @@
/**
* Configure the identity of this process to be an app UID for the duration of the
- * test. Has no effect under non-Ravenwood environments.
+ * test. Has no effect on non-Ravenwood environments.
*/
public Builder setProcessApp() {
mRule.mUid = FIRST_APPLICATION_UID;
@@ -93,7 +140,7 @@
/**
* Configure a "main" thread to be available for the duration of the test, as defined
- * by {@code Looper.getMainLooper()}. Has no effect under non-Ravenwood environments.
+ * by {@code Looper.getMainLooper()}. Has no effect on non-Ravenwood environments.
*/
public Builder setProvideMainThread(boolean provideMainThread) {
mRule.mProvideMainThread = provideMainThread;
@@ -108,7 +155,7 @@
* All properties in the {@code debug.*} namespace are automatically mutable, with no
* developer action required.
*
- * Has no effect under non-Ravenwood environments.
+ * Has no effect on non-Ravenwood environments.
*/
public Builder setSystemPropertyImmutable(/* @NonNull */ String key,
/* @Nullable */ Object value) {
@@ -125,7 +172,7 @@
* All properties in the {@code debug.*} namespace are automatically mutable, with no
* developer action required.
*
- * Has no effect under non-Ravenwood environments.
+ * Has no effect on non-Ravenwood environments.
*/
public Builder setSystemPropertyMutable(/* @NonNull */ String key,
/* @Nullable */ Object value) {
@@ -140,42 +187,51 @@
}
/**
- * Return if the current process is running under a Ravenwood test environment.
+ * @deprecated replaced by {@link #isOnRavenwood()}
*/
+ @Deprecated
public static boolean isUnderRavenwood() {
- return IS_UNDER_RAVENWOOD;
+ return IS_ON_RAVENWOOD;
}
/**
- * Determine if the given {@link Description} should be included when running under the
+ * Return if the current process is running on a Ravenwood test environment.
+ */
+ public static boolean isOnRavenwood() {
+ return IS_ON_RAVENWOOD;
+ }
+
+ /**
+ * Determine if the given {@link Description} should be enabled when running on the
* Ravenwood test environment.
*
* A more specific method-level annotation always takes precedence over any class-level
- * annotation, and an {@link IncludeUnderRavenwood} annotation always takes precedence over
- * an {@link ExcludeUnderRavenwood} annotation.
+ * annotation, and an {@link EnabledOnRavenwood} annotation always takes precedence over
+ * an {@link DisabledOnRavenwood} annotation.
*/
- private boolean shouldIncludeUnderRavenwood(Description description) {
- // Stopgap for http://g/ravenwood/EPAD-N5ntxM
- if (description.getMethodName().endsWith("$noRavenwood")) {
- return false;
- }
-
+ static boolean shouldEnableOnRavenwood(Description description) {
// First, consult any method-level annotations
- if (description.getAnnotation(IncludeUnderRavenwood.class) != null) {
- return true;
- }
- if (description.getAnnotation(ExcludeUnderRavenwood.class) != null) {
- return false;
- }
- if (description.getAnnotation(IgnoreUnderRavenwood.class) != null) {
- return false;
+ if (description.isTest()) {
+ // Stopgap for http://g/ravenwood/EPAD-N5ntxM
+ if (description.getMethodName().endsWith("$noRavenwood")) {
+ return false;
+ }
+ if (description.getAnnotation(EnabledOnRavenwood.class) != null) {
+ return true;
+ }
+ if (description.getAnnotation(DisabledOnRavenwood.class) != null) {
+ return false;
+ }
+ if (description.getAnnotation(IgnoreUnderRavenwood.class) != null) {
+ return false;
+ }
}
// Otherwise, consult any class-level annotations
- if (description.getTestClass().getAnnotation(IncludeUnderRavenwood.class) != null) {
+ if (description.getTestClass().getAnnotation(EnabledOnRavenwood.class) != null) {
return true;
}
- if (description.getTestClass().getAnnotation(ExcludeUnderRavenwood.class) != null) {
+ if (description.getTestClass().getAnnotation(DisabledOnRavenwood.class) != null) {
return false;
}
if (description.getTestClass().getAnnotation(IgnoreUnderRavenwood.class) != null) {
@@ -186,10 +242,25 @@
return true;
}
+ static boolean shouldStillIgnoreInProbeIgnoreMode(Description description) {
+ if (!ENABLE_REALLY_DISABLE_PATTERN) {
+ return false;
+ }
+
+ final var fullname = description.getTestClass().getName()
+ + (description.isTest() ? "#" + description.getMethodName() : "");
+
+ if (REALLY_DISABLE_PATTERN.matcher(fullname).find()) {
+ System.out.println("Still ignoring " + fullname);
+ return true;
+ }
+ return false;
+ }
+
@Override
public Statement apply(Statement base, Description description) {
// No special treatment when running outside Ravenwood; run tests as-is
- if (!IS_UNDER_RAVENWOOD) {
+ if (!IS_ON_RAVENWOOD) {
return base;
}
@@ -207,7 +278,7 @@
return new Statement() {
@Override
public void evaluate() throws Throwable {
- Assume.assumeTrue(shouldIncludeUnderRavenwood(description));
+ Assume.assumeTrue(shouldEnableOnRavenwood(description));
RavenwoodRuleImpl.init(RavenwoodRule.this);
try {
@@ -221,26 +292,27 @@
/**
* Run the given {@link Statement} with probing enabled. All tests will be unconditionally
- * run under Ravenwood to detect cases where a test is able to pass despite being marked as
+ * run on Ravenwood to detect cases where a test is able to pass despite being marked as
* {@code IgnoreUnderRavenwood}.
*/
private Statement applyProbeIgnored(Statement base, Description description) {
return new Statement() {
@Override
public void evaluate() throws Throwable {
+ Assume.assumeFalse(shouldStillIgnoreInProbeIgnoreMode(description));
RavenwoodRuleImpl.init(RavenwoodRule.this);
try {
base.evaluate();
} catch (Throwable t) {
// If the test isn't included, eat the exception and report the
// assumption failure that test authors expect; otherwise throw
- Assume.assumeTrue(shouldIncludeUnderRavenwood(description));
+ Assume.assumeTrue(shouldEnableOnRavenwood(description));
throw t;
} finally {
RavenwoodRuleImpl.reset(RavenwoodRule.this);
}
- if (!shouldIncludeUnderRavenwood(description)) {
+ if (!shouldEnableOnRavenwood(description)) {
fail("Test wasn't included under Ravenwood, but it actually "
+ "passed under Ravenwood; consider updating annotations");
}
diff --git a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java b/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java
index 0ff6a1a..d0c2e18 100644
--- a/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java
+++ b/ravenwood/junit-stub-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java
@@ -17,7 +17,7 @@
package android.platform.test.ravenwood;
public class RavenwoodRuleImpl {
- public static boolean isUnderRavenwood() {
+ public static boolean isOnRavenwood() {
return false;
}
diff --git a/ravenwood/mockito/test/com/android/ravenwood/mockito/RavenwoodMockitoTest.java b/ravenwood/mockito/test/com/android/ravenwood/mockito/RavenwoodMockitoTest.java
index 36fa3dd..364a86a 100644
--- a/ravenwood/mockito/test/com/android/ravenwood/mockito/RavenwoodMockitoTest.java
+++ b/ravenwood/mockito/test/com/android/ravenwood/mockito/RavenwoodMockitoTest.java
@@ -22,7 +22,6 @@
import android.content.Context;
import android.content.Intent;
-import android.platform.test.annotations.IgnoreUnderRavenwood;
import android.platform.test.ravenwood.RavenwoodRule;
import org.junit.Rule;
@@ -62,31 +61,7 @@
assertThat(object.exitValue()).isEqualTo(42);
}
- /*
- - Intent can't be mocked because of the dependency to `org.xmlpull.v1.XmlPullParser`.
- (The error says "Mockito can only mock non-private & non-final classes", but that's likely a
- red-herring.)
-
-STACKTRACE:
-org.mockito.exceptions.base.MockitoException:
-Mockito cannot mock this class: class android.content.Intent.
-
- :
-
-Underlying exception : java.lang.IllegalArgumentException: Could not create type
- at com.android.ravenwood.mockito.RavenwoodMockitoTest.testMockAndroidClass1
- at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
-
- :
-
-Caused by: java.lang.ClassNotFoundException: org.xmlpull.v1.XmlPullParser
- at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641)
- at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188)
- at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:520)
- ... 54 more
- */
@Test
- @IgnoreUnderRavenwood
public void testMockAndroidClass1() {
Intent object = mock(Intent.class);
diff --git a/ravenwood/ravenwood-annotation-allowed-classes.txt b/ravenwood/ravenwood-annotation-allowed-classes.txt
index eaf01a3..b775f9a 100644
--- a/ravenwood/ravenwood-annotation-allowed-classes.txt
+++ b/ravenwood/ravenwood-annotation-allowed-classes.txt
@@ -72,6 +72,7 @@
android.os.ServiceSpecificException
android.os.SystemClock
android.os.SystemProperties
+android.os.TestLooperManager
android.os.ThreadLocalWorkSource
android.os.TimestampedValue
android.os.Trace
@@ -141,6 +142,8 @@
android.content.ContentProvider
+android.app.Instrumentation
+
android.metrics.LogMaker
android.view.Display$HdrCapabilities
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index d656892..57c0539 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -30,10 +30,7 @@
import static android.companion.virtual.VirtualDeviceManager.EXTRA_VIRTUAL_DEVICE_ID;
import static android.content.Context.DEVICE_ID_DEFAULT;
import static android.provider.Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED;
-import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_BUTTON;
-import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_SHORTCUT_KEY;
import static android.view.accessibility.AccessibilityManager.FlashNotificationReason;
-import static android.view.accessibility.AccessibilityManager.ShortcutType;
import static com.android.internal.accessibility.AccessibilityShortcutController.ACCESSIBILITY_HEARING_AIDS_COMPONENT_NAME;
import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_COMPONENT_NAME;
@@ -142,6 +139,7 @@
import com.android.internal.accessibility.AccessibilityShortcutController;
import com.android.internal.accessibility.AccessibilityShortcutController.FrameworkFeatureInfo;
import com.android.internal.accessibility.AccessibilityShortcutController.LaunchableFrameworkFeatureInfo;
+import com.android.internal.accessibility.common.ShortcutConstants;
import com.android.internal.accessibility.dialog.AccessibilityButtonChooserActivity;
import com.android.internal.accessibility.dialog.AccessibilityShortcutChooserActivity;
import com.android.internal.accessibility.util.AccessibilityUtils;
@@ -1721,7 +1719,7 @@
}
mMainHandler.sendMessage(obtainMessage(
AccessibilityManagerService::performAccessibilityShortcutInternal, this,
- displayId, ACCESSIBILITY_BUTTON, targetName));
+ displayId, ShortcutConstants.UserShortcutType.SOFTWARE, targetName));
}
/**
@@ -2200,11 +2198,12 @@
}
private void showAccessibilityTargetsSelection(int displayId,
- @ShortcutType int shortcutType) {
+ @ShortcutConstants.UserShortcutType int shortcutType) {
final Intent intent = new Intent(AccessibilityManager.ACTION_CHOOSE_ACCESSIBILITY_BUTTON);
- final String chooserClassName = (shortcutType == ACCESSIBILITY_SHORTCUT_KEY)
- ? AccessibilityShortcutChooserActivity.class.getName()
- : AccessibilityButtonChooserActivity.class.getName();
+ final String chooserClassName =
+ (shortcutType == ShortcutConstants.UserShortcutType.HARDWARE)
+ ? AccessibilityShortcutChooserActivity.class.getName()
+ : AccessibilityButtonChooserActivity.class.getName();
intent.setClassName(CHOOSER_PACKAGE_NAME, chooserClassName);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
final Bundle bundle = ActivityOptions.makeBasic().setLaunchDisplayId(displayId).toBundle();
@@ -3275,7 +3274,7 @@
}
final Set<String> currentTargets =
- userState.getShortcutTargetsLocked(ACCESSIBILITY_SHORTCUT_KEY);
+ userState.getShortcutTargetsLocked(ShortcutConstants.UserShortcutType.HARDWARE);
if (targetsFromSetting.equals(currentTargets)) {
return false;
}
@@ -3291,7 +3290,7 @@
userState.mUserId, str -> str, targetsFromSetting);
final Set<String> currentTargets =
- userState.getShortcutTargetsLocked(ACCESSIBILITY_BUTTON);
+ userState.getShortcutTargetsLocked(ShortcutConstants.UserShortcutType.SOFTWARE);
if (targetsFromSetting.equals(currentTargets)) {
return false;
}
@@ -3346,7 +3345,7 @@
*/
private void updateAccessibilityShortcutKeyTargetsLocked(AccessibilityUserState userState) {
final Set<String> currentTargets =
- userState.getShortcutTargetsLocked(ACCESSIBILITY_SHORTCUT_KEY);
+ userState.getShortcutTargetsLocked(ShortcutConstants.UserShortcutType.HARDWARE);
final int lastSize = currentTargets.size();
if (lastSize == 0) {
return;
@@ -3531,7 +3530,7 @@
}
final Set<String> currentTargets =
- userState.getShortcutTargetsLocked(ACCESSIBILITY_BUTTON);
+ userState.getShortcutTargetsLocked(ShortcutConstants.UserShortcutType.SOFTWARE);
final int lastSize = currentTargets.size();
if (lastSize == 0) {
return;
@@ -3571,7 +3570,7 @@
return;
}
final Set<String> buttonTargets =
- userState.getShortcutTargetsLocked(ACCESSIBILITY_BUTTON);
+ userState.getShortcutTargetsLocked(ShortcutConstants.UserShortcutType.SOFTWARE);
int lastSize = buttonTargets.size();
buttonTargets.removeIf(name -> {
if (packageName != null && name != null && !name.contains(packageName)) {
@@ -3608,7 +3607,7 @@
lastSize = buttonTargets.size();
final Set<String> shortcutKeyTargets =
- userState.getShortcutTargetsLocked(ACCESSIBILITY_SHORTCUT_KEY);
+ userState.getShortcutTargetsLocked(ShortcutConstants.UserShortcutType.HARDWARE);
userState.mEnabledServices.forEach(componentName -> {
if (packageName != null && componentName != null
&& !packageName.equals(componentName.getPackageName())) {
@@ -3665,16 +3664,18 @@
return;
}
final ComponentName serviceName = service.getComponentName();
- if (userState.removeShortcutTargetLocked(ACCESSIBILITY_SHORTCUT_KEY, serviceName)) {
+ if (userState.removeShortcutTargetLocked(
+ ShortcutConstants.UserShortcutType.HARDWARE, serviceName)) {
final Set<String> currentTargets = userState.getShortcutTargetsLocked(
- ACCESSIBILITY_SHORTCUT_KEY);
+ ShortcutConstants.UserShortcutType.HARDWARE);
persistColonDelimitedSetToSettingLocked(
Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE,
userState.mUserId, currentTargets, str -> str);
}
- if (userState.removeShortcutTargetLocked(ACCESSIBILITY_BUTTON, serviceName)) {
+ if (userState.removeShortcutTargetLocked(
+ ShortcutConstants.UserShortcutType.SOFTWARE, serviceName)) {
final Set<String> currentTargets = userState.getShortcutTargetsLocked(
- ACCESSIBILITY_BUTTON);
+ ShortcutConstants.UserShortcutType.SOFTWARE);
persistColonDelimitedSetToSettingLocked(Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS,
userState.mUserId, currentTargets, str -> str);
}
@@ -3750,7 +3751,7 @@
}
mMainHandler.sendMessage(obtainMessage(
AccessibilityManagerService::performAccessibilityShortcutInternal, this,
- Display.DEFAULT_DISPLAY, ACCESSIBILITY_SHORTCUT_KEY, targetName));
+ Display.DEFAULT_DISPLAY, ShortcutConstants.UserShortcutType.HARDWARE, targetName));
}
/**
@@ -3763,7 +3764,7 @@
* specified target.
*/
private void performAccessibilityShortcutInternal(int displayId,
- @ShortcutType int shortcutType, @Nullable String targetName) {
+ @ShortcutConstants.UserShortcutType int shortcutType, @Nullable String targetName) {
final List<String> shortcutTargets = getAccessibilityShortcutTargetsInternal(shortcutType);
if (shortcutTargets.isEmpty()) {
Slog.d(LOG_TAG, "No target to perform shortcut, shortcutType=" + shortcutType);
@@ -3814,7 +3815,7 @@
}
private boolean performAccessibilityFrameworkFeature(int displayId,
- ComponentName assignedTarget, @ShortcutType int shortcutType) {
+ ComponentName assignedTarget, @ShortcutConstants.UserShortcutType int shortcutType) {
final Map<ComponentName, FrameworkFeatureInfo> frameworkFeatureMap =
AccessibilityShortcutController.getFrameworkShortcutFeaturesMap();
if (!frameworkFeatureMap.containsKey(assignedTarget)) {
@@ -3863,12 +3864,12 @@
/**
* Perform accessibility service shortcut action.
*
- * 1) For {@link AccessibilityManager#ACCESSIBILITY_BUTTON} type and services targeting sdk
+ * 1) For {@link ShortcutConstants.UserShortcutType.SOFTWARE} type and services targeting sdk
* version <= Q: callbacks to accessibility service if service is bounded and requests
* accessibility button.
- * 2) For {@link AccessibilityManager#ACCESSIBILITY_SHORTCUT_KEY} type and service targeting sdk
+ * 2) For {@link ShortcutConstants.UserShortcutType.HARDWARE} type and service targeting sdk
* version <= Q: turns on / off the accessibility service.
- * 3) For {@link AccessibilityManager#ACCESSIBILITY_SHORTCUT_KEY} type and service targeting sdk
+ * 3) For {@link ShortcutConstants.UserShortcutType.HARDWARE} type and service targeting sdk
* version > Q and request accessibility button: turn on the accessibility service if it's
* not in the enabled state.
* (It'll happen when a service is disabled and assigned to shortcut then upgraded.)
@@ -3879,7 +3880,7 @@
* button.
*/
private boolean performAccessibilityShortcutTargetService(int displayId,
- @ShortcutType int shortcutType, ComponentName assignedTarget) {
+ @ShortcutConstants.UserShortcutType int shortcutType, ComponentName assignedTarget) {
synchronized (mLock) {
final AccessibilityUserState userState = getCurrentUserStateLocked();
final AccessibilityServiceInfo installedServiceInfo =
@@ -3897,7 +3898,8 @@
final boolean requestA11yButton = (installedServiceInfo.flags
& FLAG_REQUEST_ACCESSIBILITY_BUTTON) != 0;
// Turns on / off the accessibility service
- if ((targetSdk <= Build.VERSION_CODES.Q && shortcutType == ACCESSIBILITY_SHORTCUT_KEY)
+ if ((targetSdk <= Build.VERSION_CODES.Q
+ && shortcutType == ShortcutConstants.UserShortcutType.HARDWARE)
|| (targetSdk > Build.VERSION_CODES.Q && !requestA11yButton)) {
if (serviceConnection == null) {
logAccessibilityShortcutActivated(mContext, assignedTarget, shortcutType,
@@ -3911,7 +3913,8 @@
}
return true;
}
- if (shortcutType == ACCESSIBILITY_SHORTCUT_KEY && targetSdk > Build.VERSION_CODES.Q
+ if (shortcutType == ShortcutConstants.UserShortcutType.HARDWARE
+ && targetSdk > Build.VERSION_CODES.Q
&& requestA11yButton) {
if (!userState.getEnabledServicesLocked().contains(assignedTarget)) {
enableAccessibilityServiceLocked(assignedTarget, mCurrentUserId);
@@ -3941,7 +3944,8 @@
}
@Override
- public List<String> getAccessibilityShortcutTargets(@ShortcutType int shortcutType) {
+ public List<String> getAccessibilityShortcutTargets(
+ @ShortcutConstants.UserShortcutType int shortcutType) {
if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) {
mTraceManager.logTrace(LOG_TAG + ".getAccessibilityShortcutTargets",
FLAGS_ACCESSIBILITY_MANAGER, "shortcutType=" + shortcutType);
@@ -3955,12 +3959,13 @@
return getAccessibilityShortcutTargetsInternal(shortcutType);
}
- private List<String> getAccessibilityShortcutTargetsInternal(@ShortcutType int shortcutType) {
+ private List<String> getAccessibilityShortcutTargetsInternal(
+ @ShortcutConstants.UserShortcutType int shortcutType) {
synchronized (mLock) {
final AccessibilityUserState userState = getCurrentUserStateLocked();
final ArrayList<String> shortcutTargets = new ArrayList<>(
userState.getShortcutTargetsLocked(shortcutType));
- if (shortcutType != ACCESSIBILITY_BUTTON) {
+ if (shortcutType != ShortcutConstants.UserShortcutType.SOFTWARE) {
return shortcutTargets;
}
// Adds legacy a11y services requesting a11y button into the list.
@@ -4423,7 +4428,7 @@
}
}
// Warning is not required if the service is already assigned to a shortcut.
- for (int shortcutType : AccessibilityManager.SHORTCUT_TYPES) {
+ for (int shortcutType : ShortcutConstants.USER_SHORTCUT_TYPES) {
if (getAccessibilityShortcutTargets(shortcutType).contains(
componentName.flattenToString())) {
return false;
@@ -4603,8 +4608,8 @@
public void onShellCommand(FileDescriptor in, FileDescriptor out,
FileDescriptor err, String[] args, ShellCallback callback,
ResultReceiver resultReceiver) {
- new AccessibilityShellCommand(this, mSystemActionPerformer).exec(this, in, out, err, args,
- callback, resultReceiver);
+ new AccessibilityShellCommand(this, mSystemActionPerformer)
+ .exec(this, in, out, err, args, callback, resultReceiver);
}
private final class InteractionBridge {
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java
index 68ee780..41165b6 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java
@@ -24,9 +24,6 @@
import static android.accessibilityservice.AccessibilityService.SHOW_MODE_MASK;
import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN;
import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_NONE;
-import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_BUTTON;
-import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_SHORTCUT_KEY;
-import static android.view.accessibility.AccessibilityManager.ShortcutType;
import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_CONTROLLER_NAME;
@@ -51,6 +48,7 @@
import com.android.internal.R;
import com.android.internal.accessibility.AccessibilityShortcutController;
+import com.android.internal.accessibility.common.ShortcutConstants;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -757,13 +755,21 @@
* @param shortcutType The shortcut type.
* @return The array set of the strings
*/
- public ArraySet<String> getShortcutTargetsLocked(@ShortcutType int shortcutType) {
- if (shortcutType == ACCESSIBILITY_SHORTCUT_KEY) {
+ public ArraySet<String> getShortcutTargetsLocked(
+ @ShortcutConstants.UserShortcutType int shortcutType) {
+ if (shortcutType == ShortcutConstants.UserShortcutType.HARDWARE) {
return mAccessibilityShortcutKeyTargets;
- } else if (shortcutType == ACCESSIBILITY_BUTTON) {
+ } else if (shortcutType == ShortcutConstants.UserShortcutType.SOFTWARE) {
return mAccessibilityButtonTargets;
+ } else if ((shortcutType == ShortcutConstants.UserShortcutType.TRIPLETAP
+ && isMagnificationSingleFingerTripleTapEnabledLocked()) || (
+ shortcutType == ShortcutConstants.UserShortcutType.TWO_FINGERS_TRIPLE_TAP
+ && isMagnificationTwoFingerTripleTapEnabledLocked())) {
+ ArraySet<String> targets = new ArraySet<>();
+ targets.add(MAGNIFICATION_CONTROLLER_NAME);
+ return targets;
}
- return null;
+ return new ArraySet<>();
}
/**
@@ -802,12 +808,22 @@
/**
* Removes given shortcut target in the list.
*
- * @param shortcutType The shortcut type.
- * @param target The component name of the shortcut target.
+ * @param shortcutType one of {@link ShortcutConstants.UserShortcutType.HARDWARE} or
+ * {@link ShortcutConstants.UserShortcutType.SOFTWARE}. Other types are not
+ * implemented.
+ * @param target The component name of the shortcut target.
* @return true if the shortcut target is removed.
*/
- public boolean removeShortcutTargetLocked(@ShortcutType int shortcutType,
+ public boolean removeShortcutTargetLocked(@ShortcutConstants.UserShortcutType int shortcutType,
ComponentName target) {
+ if (shortcutType == ShortcutConstants.UserShortcutType.TRIPLETAP
+ || shortcutType == ShortcutConstants.UserShortcutType.TWO_FINGERS_TRIPLE_TAP) {
+ throw new UnsupportedOperationException(
+ "removeShortcutTargetLocked only support shortcut type: "
+ + "software and hardware for now"
+ );
+ }
+
return getShortcutTargetsLocked(shortcutType).removeIf(name -> {
ComponentName componentName;
if (name == null
diff --git a/services/autofill/java/com/android/server/autofill/RemoteFillService.java b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
index 5c93991..f914ed5 100644
--- a/services/autofill/java/com/android/server/autofill/RemoteFillService.java
+++ b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
@@ -31,9 +31,12 @@
import android.os.ICancellationSignal;
import android.os.RemoteException;
import android.service.autofill.AutofillService;
+import android.service.autofill.ConvertCredentialRequest;
+import android.service.autofill.ConvertCredentialResponse;
import android.service.autofill.FillRequest;
import android.service.autofill.FillResponse;
import android.service.autofill.IAutoFillService;
+import android.service.autofill.IConvertCredentialCallback;
import android.service.autofill.IFillCallback;
import android.service.autofill.ISaveCallback;
import android.service.autofill.SaveRequest;
@@ -69,6 +72,7 @@
private int mPendingFillRequestId = INVALID_REQUEST_ID;
private AtomicReference<IFillCallback> mFillCallback;
private AtomicReference<ISaveCallback> mSaveCallback;
+ private AtomicReference<IConvertCredentialCallback> mConvertCredentialCallback;
private final ComponentName mComponentName;
private final boolean mIsCredentialAutofillService;
@@ -81,13 +85,20 @@
extends AbstractRemoteService.VultureCallback<RemoteFillService> {
void onFillRequestSuccess(int requestId, @Nullable FillResponse response,
@NonNull String servicePackageName, int requestFlags);
+
void onFillRequestFailure(int requestId, @Nullable CharSequence message);
+
void onFillRequestTimeout(int requestId);
+
void onSaveRequestSuccess(@NonNull String servicePackageName,
@Nullable IntentSender intentSender);
+
// TODO(b/80093094): add timeout here too?
void onSaveRequestFailure(@Nullable CharSequence message,
@NonNull String servicePackageName);
+
+ void onConvertCredentialRequestSuccess(@NonNull ConvertCredentialResponse
+ convertCredentialResponse);
}
RemoteFillService(Context context, ComponentName componentName, int userId,
@@ -211,6 +222,32 @@
}
}
+ static class IConvertCredentialCallbackDelegate extends IConvertCredentialCallback.Stub {
+
+ private WeakReference<IConvertCredentialCallback> mCallbackWeakRef;
+
+ IConvertCredentialCallbackDelegate(IConvertCredentialCallback callback) {
+ mCallbackWeakRef = new WeakReference(callback);
+ }
+
+ @Override
+ public void onSuccess(ConvertCredentialResponse convertCredentialResponse)
+ throws RemoteException {
+ IConvertCredentialCallback callback = mCallbackWeakRef.get();
+ if (callback != null) {
+ callback.onSuccess(convertCredentialResponse);
+ }
+ }
+
+ @Override
+ public void onFailure(CharSequence message) throws RemoteException {
+ IConvertCredentialCallback callback = mCallbackWeakRef.get();
+ if (callback != null) {
+ callback.onFailure(message);
+ }
+ }
+ }
+
/**
* Wraps an {@link IFillCallback} object using weak reference.
*
@@ -237,6 +274,18 @@
return callback;
}
+ /**
+ * Wraps an {@link IConvertCredentialCallback} object using weak reference
+ */
+ private IConvertCredentialCallback maybeWrapWithWeakReference(
+ IConvertCredentialCallback callback) {
+ if (remoteFillServiceUseWeakReference()) {
+ mConvertCredentialCallback = new AtomicReference<>(callback);
+ return new IConvertCredentialCallbackDelegate(callback);
+ }
+ return callback;
+ }
+
public void onFillCredentialRequest(@NonNull FillRequest request,
IAutoFillManagerClient autofillCallback) {
if (sVerbose) {
@@ -378,6 +427,52 @@
}));
}
+ public void onConvertCredentialRequest(
+ @NonNull ConvertCredentialRequest convertCredentialRequest) {
+ if (sVerbose) Slog.v(TAG, "calling onConvertCredentialRequest()");
+ CompletableFuture<ConvertCredentialResponse>
+ connectThenConvertCredentialRequest = postAsync(
+ remoteService -> {
+ if (sVerbose) {
+ Slog.v(TAG, "calling onConvertCredentialRequest()");
+ }
+ CompletableFuture<ConvertCredentialResponse>
+ convertCredentialCompletableFuture = new CompletableFuture<>();
+ remoteService.onConvertCredentialRequest(convertCredentialRequest,
+ maybeWrapWithWeakReference(
+ new IConvertCredentialCallback.Stub() {
+ @Override
+ public void onSuccess(ConvertCredentialResponse
+ convertCredentialResponse) {
+ convertCredentialCompletableFuture
+ .complete(convertCredentialResponse);
+ }
+
+ @Override
+ public void onFailure(CharSequence message) {
+ String errorMessage =
+ message == null ? "" :
+ String.valueOf(message);
+ convertCredentialCompletableFuture
+ .completeExceptionally(
+ new RuntimeException(errorMessage));
+ }
+ })
+ );
+ return convertCredentialCompletableFuture;
+ }).orTimeout(TIMEOUT_REMOTE_REQUEST_MILLIS, TimeUnit.MILLISECONDS);
+
+ connectThenConvertCredentialRequest.whenComplete(
+ (res, err) -> Handler.getMain().post(() -> {
+ if (err == null) {
+ mCallbacks.onConvertCredentialRequestSuccess(res);
+ } else {
+ // TODO: Add a callback function to log this failure
+ Slog.e(TAG, "Error calling on convert credential request", err);
+ }
+ }));
+ }
+
public void onSaveRequest(@NonNull SaveRequest request) {
postAsync(service -> {
if (sVerbose) Slog.v(TAG, "calling onSaveRequest()");
diff --git a/services/autofill/java/com/android/server/autofill/SecondaryProviderHandler.java b/services/autofill/java/com/android/server/autofill/SecondaryProviderHandler.java
index 1234703..0af703e 100644
--- a/services/autofill/java/com/android/server/autofill/SecondaryProviderHandler.java
+++ b/services/autofill/java/com/android/server/autofill/SecondaryProviderHandler.java
@@ -25,6 +25,7 @@
import android.content.Context;
import android.content.IntentSender;
import android.os.Bundle;
+import android.service.autofill.ConvertCredentialResponse;
import android.service.autofill.FillRequest;
import android.service.autofill.FillResponse;
import android.util.Slog;
@@ -98,6 +99,12 @@
}
+ @Override
+ public void onConvertCredentialRequestSuccess(@NonNull ConvertCredentialResponse
+ convertCredentialResponse) {
+
+ }
+
/**
* Requests a new fill response.
*/
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index f3b74ea..049feee 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -24,6 +24,7 @@
import static android.service.autofill.Dataset.PICK_REASON_PROVIDER_DETECTION_ONLY;
import static android.service.autofill.Dataset.PICK_REASON_PROVIDER_DETECTION_PREFERRED_WITH_PCC;
import static android.service.autofill.Dataset.PICK_REASON_UNKNOWN;
+import static android.service.autofill.FillEventHistory.Event.UI_TYPE_CREDMAN_BOTTOM_SHEET;
import static android.service.autofill.FillEventHistory.Event.UI_TYPE_DIALOG;
import static android.service.autofill.FillEventHistory.Event.UI_TYPE_INLINE;
import static android.service.autofill.FillEventHistory.Event.UI_TYPE_MENU;
@@ -44,6 +45,7 @@
import static android.view.autofill.AutofillManager.ACTION_VIEW_EXITED;
import static android.view.autofill.AutofillManager.COMMIT_REASON_SESSION_DESTROYED;
import static android.view.autofill.AutofillManager.COMMIT_REASON_UNKNOWN;
+import static android.view.autofill.AutofillManager.EXTRA_AUTOFILL_REQUEST_ID;
import static android.view.autofill.AutofillManager.FLAG_SMART_SUGGESTION_SYSTEM;
import static android.view.autofill.AutofillManager.getSmartSuggestionModeToString;
@@ -130,6 +132,7 @@
import android.service.autofill.AutofillFieldClassificationService.Scores;
import android.service.autofill.AutofillService;
import android.service.autofill.CompositeUserData;
+import android.service.autofill.ConvertCredentialResponse;
import android.service.autofill.Dataset;
import android.service.autofill.Dataset.DatasetEligibleReason;
import android.service.autofill.Field;
@@ -2429,6 +2432,29 @@
removeFromService();
}
+ // FillServiceCallbacks
+ @Override
+ public void onConvertCredentialRequestSuccess(@NonNull ConvertCredentialResponse
+ convertCredentialResponse) {
+ Dataset dataset = convertCredentialResponse.getDataset();
+ Bundle clientState = convertCredentialResponse.getClientState();
+ if (dataset != null) {
+ int requestId = -1;
+ if (clientState != null) {
+ requestId = clientState.getInt(EXTRA_AUTOFILL_REQUEST_ID);
+ } else {
+ Slog.e(TAG, "onConvertCredentialRequestSuccess(): client state is null, this "
+ + "would cause loss in logging.");
+ }
+ // TODO: Add autofill related logging; consider whether to log the index
+ fill(requestId, /* datasetIndex=*/ -1, dataset, UI_TYPE_CREDMAN_BOTTOM_SHEET);
+ } else {
+ // TODO: Add logging to log this error case
+ Slog.e(TAG, "onConvertCredentialRequestSuccess(): dataset inside response is "
+ + "null");
+ }
+ }
+
/**
* Gets the {@link FillContext} for a request.
*
diff --git a/services/companion/java/com/android/server/companion/InactiveAssociationsRemovalService.java b/services/companion/java/com/android/server/companion/InactiveAssociationsRemovalService.java
index 3482863..aac628c 100644
--- a/services/companion/java/com/android/server/companion/InactiveAssociationsRemovalService.java
+++ b/services/companion/java/com/android/server/companion/InactiveAssociationsRemovalService.java
@@ -36,7 +36,8 @@
* will be killed if association/role are revoked.
*/
public class InactiveAssociationsRemovalService extends JobService {
- private static final int JOB_ID = InactiveAssociationsRemovalService.class.hashCode();
+ private static final String JOB_NAMESPACE = "companion";
+ private static final int JOB_ID = 1;
private static final long ONE_DAY_INTERVAL = DAYS.toMillis(1);
@Override
@@ -61,7 +62,8 @@
static void schedule(Context context) {
Slog.i(TAG, "Scheduling the Association Removal job");
- final JobScheduler jobScheduler = context.getSystemService(JobScheduler.class);
+ final JobScheduler jobScheduler =
+ context.getSystemService(JobScheduler.class).forNamespace(JOB_NAMESPACE);
final JobInfo job = new JobInfo.Builder(JOB_ID,
new ComponentName(context, InactiveAssociationsRemovalService.class))
.setRequiresCharging(true)
@@ -71,4 +73,3 @@
jobScheduler.schedule(job);
}
}
-
diff --git a/services/core/Android.bp b/services/core/Android.bp
index a54a48a..8e35b74 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -139,6 +139,7 @@
libs: [
"services.net",
+ "android.frameworks.location.altitude-V2-java",
"android.hardware.common-V2-java",
"android.hardware.light-V2.0-java",
"android.hardware.gnss-V2-java",
@@ -160,7 +161,6 @@
],
static_libs: [
- "android.frameworks.location.altitude-V2-java", // AIDL
"android.frameworks.vibrator-V1-java", // AIDL
"android.hardware.authsecret-V1.0-java",
"android.hardware.authsecret-V1-java",
diff --git a/services/core/java/com/android/server/BinderCallsStatsService.java b/services/core/java/com/android/server/BinderCallsStatsService.java
index b87184a..416b36f 100644
--- a/services/core/java/com/android/server/BinderCallsStatsService.java
+++ b/services/core/java/com/android/server/BinderCallsStatsService.java
@@ -288,22 +288,23 @@
CachedDeviceState.Readonly.class);
mBinderCallsStats.setDeviceState(deviceState);
- BatteryStatsInternal batteryStatsInternal = getLocalService(
- BatteryStatsInternal.class);
- mBinderCallsStats.setCallStatsObserver(new BinderInternal.CallStatsObserver() {
- @Override
- public void noteCallStats(int workSourceUid, long incrementalCallCount,
- Collection<BinderCallsStats.CallStat> callStats) {
- batteryStatsInternal.noteBinderCallStats(workSourceUid,
- incrementalCallCount, callStats);
- }
+ if (!com.android.server.power.optimization.Flags.disableSystemServicePowerAttr()) {
+ BatteryStatsInternal batteryStatsInternal = getLocalService(
+ BatteryStatsInternal.class);
+ mBinderCallsStats.setCallStatsObserver(new BinderInternal.CallStatsObserver() {
+ @Override
+ public void noteCallStats(int workSourceUid, long incrementalCallCount,
+ Collection<BinderCallsStats.CallStat> callStats) {
+ batteryStatsInternal.noteBinderCallStats(workSourceUid,
+ incrementalCallCount, callStats);
+ }
- @Override
- public void noteBinderThreadNativeIds(int[] binderThreadNativeTids) {
- batteryStatsInternal.noteBinderThreadNativeIds(binderThreadNativeTids);
- }
- });
-
+ @Override
+ public void noteBinderThreadNativeIds(int[] binderThreadNativeTids) {
+ batteryStatsInternal.noteBinderThreadNativeIds(binderThreadNativeTids);
+ }
+ });
+ }
// It needs to be called before mService.systemReady to make sure the observer is
// initialized before installing it.
mWorkSourceProvider.systemReady(getContext());
diff --git a/services/core/java/com/android/server/SensitiveContentProtectionManagerService.java b/services/core/java/com/android/server/SensitiveContentProtectionManagerService.java
index c391642..f619ca3 100644
--- a/services/core/java/com/android/server/SensitiveContentProtectionManagerService.java
+++ b/services/core/java/com/android/server/SensitiveContentProtectionManagerService.java
@@ -27,6 +27,7 @@
import android.os.Handler;
import android.os.Looper;
import android.os.RemoteException;
+import android.os.Trace;
import android.os.UserHandle;
import android.service.notification.NotificationListenerService;
import android.service.notification.NotificationListenerService.RankingMap;
@@ -49,12 +50,12 @@
private static final String TAG = "SensitiveContentProtect";
private static final boolean DEBUG = false;
- @VisibleForTesting
- NotificationListener mNotificationListener;
+ @VisibleForTesting NotificationListener mNotificationListener;
private @Nullable MediaProjectionManager mProjectionManager;
private @Nullable WindowManagerInternal mWindowManager;
final Object mSensitiveContentProtectionLock = new Object();
+
@GuardedBy("mSensitiveContentProtectionLock")
private boolean mProjectionActive = false;
@@ -63,13 +64,24 @@
@Override
public void onStart(MediaProjectionInfo info) {
if (DEBUG) Log.d(TAG, "onStart projection: " + info);
- onProjectionStart();
+ Trace.beginSection(
+ "SensitiveContentProtectionManagerService.onProjectionStart");
+ try {
+ onProjectionStart();
+ } finally {
+ Trace.endSection();
+ }
}
@Override
public void onStop(MediaProjectionInfo info) {
if (DEBUG) Log.d(TAG, "onStop projection: " + info);
- onProjectionEnd();
+ Trace.beginSection("SensitiveContentProtectionManagerService.onProjectionStop");
+ try {
+ onProjectionEnd();
+ } finally {
+ Trace.endSection();
+ }
}
};
@@ -94,8 +106,7 @@
}
@VisibleForTesting
- void init(MediaProjectionManager projectionManager,
- WindowManagerInternal windowManager) {
+ void init(MediaProjectionManager projectionManager, WindowManagerInternal windowManager) {
if (DEBUG) Log.d(TAG, "init");
checkNotNull(projectionManager, "Failed to get valid MediaProjectionManager");
@@ -109,7 +120,8 @@
mProjectionManager.addCallback(mProjectionCallback, new Handler(Looper.getMainLooper()));
try {
- mNotificationListener.registerAsSystemService(getContext(),
+ mNotificationListener.registerAsSystemService(
+ getContext(),
new ComponentName(getContext(), NotificationListener.class),
UserHandle.USER_ALL);
} catch (RemoteException e) {
@@ -174,8 +186,8 @@
}
// notify windowmanager of any currently posted sensitive content notifications
- ArraySet<PackageInfo> packageInfos = getSensitivePackagesFromNotifications(
- notifications, rankingMap);
+ ArraySet<PackageInfo> packageInfos =
+ getSensitivePackagesFromNotifications(notifications, rankingMap);
mWindowManager.addBlockScreenCaptureForApps(packageInfos);
}
@@ -197,8 +209,8 @@
return sensitivePackages;
}
- private PackageInfo getSensitivePackageFromNotification(StatusBarNotification sbn,
- RankingMap rankingMap) {
+ private PackageInfo getSensitivePackageFromNotification(
+ StatusBarNotification sbn, RankingMap rankingMap) {
if (sbn == null) {
Log.w(TAG, "Unable to protect null notification");
return null;
@@ -220,38 +232,55 @@
@Override
public void onListenerConnected() {
super.onListenerConnected();
- // Projection started before notification listener was connected
- synchronized (mSensitiveContentProtectionLock) {
- if (mProjectionActive) {
- updateAppsThatShouldBlockScreenCapture();
+ Trace.beginSection("SensitiveContentProtectionManagerService.onListenerConnected");
+ try {
+ // Projection started before notification listener was connected
+ synchronized (mSensitiveContentProtectionLock) {
+ if (mProjectionActive) {
+ updateAppsThatShouldBlockScreenCapture();
+ }
}
+ } finally {
+ Trace.endSection();
}
}
@Override
public void onNotificationPosted(StatusBarNotification sbn, RankingMap rankingMap) {
super.onNotificationPosted(sbn, rankingMap);
- synchronized (mSensitiveContentProtectionLock) {
- if (!mProjectionActive) {
- return;
- }
+ Trace.beginSection("SensitiveContentProtectionManagerService.onNotificationPosted");
+ try {
+ synchronized (mSensitiveContentProtectionLock) {
+ if (!mProjectionActive) {
+ return;
+ }
- // notify windowmanager of any currently posted sensitive content notifications
- PackageInfo packageInfo = getSensitivePackageFromNotification(sbn, rankingMap);
+ // notify windowmanager of any currently posted sensitive content notifications
+ PackageInfo packageInfo = getSensitivePackageFromNotification(sbn, rankingMap);
- if (packageInfo != null) {
- mWindowManager.addBlockScreenCaptureForApps(new ArraySet(Set.of(packageInfo)));
+ if (packageInfo != null) {
+ mWindowManager.addBlockScreenCaptureForApps(
+ new ArraySet(Set.of(packageInfo)));
+ }
}
+ } finally {
+ Trace.endSection();
}
}
@Override
public void onNotificationRankingUpdate(RankingMap rankingMap) {
super.onNotificationRankingUpdate(rankingMap);
- synchronized (mSensitiveContentProtectionLock) {
- if (mProjectionActive) {
- updateAppsThatShouldBlockScreenCapture(rankingMap);
+ Trace.beginSection(
+ "SensitiveContentProtectionManagerService.onNotificationRankingUpdate");
+ try {
+ synchronized (mSensitiveContentProtectionLock) {
+ if (mProjectionActive) {
+ updateAppsThatShouldBlockScreenCapture(rankingMap);
+ }
}
+ } finally {
+ Trace.endSection();
}
}
}
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index afb8345..adc0255 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -181,7 +181,6 @@
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.content.pm.ServiceInfo.ForegroundServiceType;
-import android.os.Binder;
import android.os.Build;
import android.os.Build.VERSION_CODES;
import android.os.Bundle;
@@ -306,6 +305,57 @@
@interface FgsStopReason {}
/**
+ * The policy to be applied to the service bindings; this one means it follows the legacy
+ * behavior.
+ */
+ static final int SERVICE_BIND_OOMADJ_POLICY_LEGACY = 0;
+
+ /**
+ * The policy to be applied to the service bindings; this one means we'll skip
+ * updating the target process's oom adj score / process state for its {@link Service#onCreate}.
+ */
+ static final int SERVICE_BIND_OOMADJ_POLICY_SKIP_OOM_UPDATE_ON_CREATE = 1;
+
+ /**
+ * The policy to be applied to the service bindings; this one means we'll skip
+ * updating the target process's oom adj score / process state for its {@link Service#onBind}.
+ */
+ static final int SERVICE_BIND_OOMADJ_POLICY_SKIP_OOM_UPDATE_ON_BIND = 1 << 1;
+
+ /**
+ * The policy to be applied to the service bindings; this one means we'll skip
+ * updating the target process's oom adj score / process state on setting up the service
+ * connection between the client and the service host process.
+ */
+ static final int SERVICE_BIND_OOMADJ_POLICY_SKIP_OOM_UPDATE_ON_CONNECT = 1 << 2;
+ /**
+ * The policy to be applied to the service bindings; this one means the caller
+ * will be frozen upon calling the bindService APIs.
+ */
+ static final int SERVICE_BIND_OOMADJ_POLICY_FREEZE_CALLER = 1 << 3;
+
+ @IntDef(flag = true, prefix = { "SERVICE_BIND_OOMADJ_POLICY_" }, value = {
+ SERVICE_BIND_OOMADJ_POLICY_LEGACY,
+ SERVICE_BIND_OOMADJ_POLICY_SKIP_OOM_UPDATE_ON_CREATE,
+ SERVICE_BIND_OOMADJ_POLICY_SKIP_OOM_UPDATE_ON_BIND,
+ SERVICE_BIND_OOMADJ_POLICY_SKIP_OOM_UPDATE_ON_CONNECT,
+ SERVICE_BIND_OOMADJ_POLICY_FREEZE_CALLER,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @interface ServiceBindingOomAdjPolicy {}
+
+ @ServiceBindingOomAdjPolicy
+ static final int DEFAULT_SERVICE_NO_BUMP_BIND_POLICY_FLAG =
+ SERVICE_BIND_OOMADJ_POLICY_SKIP_OOM_UPDATE_ON_CREATE
+ | SERVICE_BIND_OOMADJ_POLICY_SKIP_OOM_UPDATE_ON_BIND
+ | SERVICE_BIND_OOMADJ_POLICY_SKIP_OOM_UPDATE_ON_CONNECT;
+
+ @ServiceBindingOomAdjPolicy
+ static final int DEFAULT_SERVICE_CACHED_BIND_POLICY_FLAG =
+ SERVICE_BIND_OOMADJ_POLICY_SKIP_OOM_UPDATE_ON_CREATE
+ | SERVICE_BIND_OOMADJ_POLICY_SKIP_OOM_UPDATE_ON_BIND;
+
+ /**
* Disables foreground service background starts from BOOT_COMPLETED broadcasts for all types
* except:
* <ul>
@@ -1244,7 +1294,7 @@
@Override
public void onResult(Bundle result) {
synchronized (mAm) {
- final long identity = Binder.clearCallingIdentity();
+ final long identity = mAm.mInjector.clearCallingIdentity();
try {
if (!mPendingServices.contains(r)) {
return;
@@ -1263,7 +1313,8 @@
false /* whileRestarting */,
false /* permissionsReviewRequired */,
false /* packageFrozen */,
- true /* enqueueOomAdj */);
+ true /* enqueueOomAdj */,
+ SERVICE_BIND_OOMADJ_POLICY_LEGACY);
} catch (RemoteException e) {
/* ignore - local call */
} finally {
@@ -1275,7 +1326,7 @@
unbindServiceLocked(connection);
}
} finally {
- Binder.restoreCallingIdentity(identity);
+ mAm.mInjector.restoreCallingIdentity(identity);
}
}
}
@@ -1353,7 +1404,8 @@
false /* whileRestarting */,
false /* permissionsReviewRequired */,
false /* packageFrozen */,
- true /* enqueueOomAdj */);
+ true /* enqueueOomAdj */,
+ SERVICE_BIND_OOMADJ_POLICY_LEGACY);
} catch (TransactionTooLargeException e) {
/* ignore - local call */
} finally {
@@ -1431,7 +1483,8 @@
false /* whileRestarting */,
false /* permissionsReviewRequired */,
false /* packageFrozen */,
- true /* enqueueOomAdj */);
+ true /* enqueueOomAdj */,
+ SERVICE_BIND_OOMADJ_POLICY_LEGACY);
/* Will be a no-op if nothing pending */
mAm.updateOomAdjPendingTargetsLocked(OOM_ADJ_REASON_START_SERVICE);
if (error != null) {
@@ -1550,22 +1603,22 @@
if (caller != null && callerApp == null) {
throw new SecurityException(
"Unable to find app for caller " + caller
- + " (pid=" + Binder.getCallingPid()
+ + " (pid=" + mAm.mInjector.getCallingPid()
+ ") when stopping service " + service);
}
// If this service is active, make sure it is stopped.
ServiceLookupResult r = retrieveServiceLocked(service, instanceName, isSdkSandboxService,
sdkSandboxClientAppUid, sdkSandboxClientAppPackage, resolvedType, null,
- Binder.getCallingPid(), Binder.getCallingUid(), userId, false, false, false, false,
- null, false, false);
+ mAm.mInjector.getCallingPid(), mAm.mInjector.getCallingUid(),
+ userId, false, false, false, false, null, false, false);
if (r != null) {
if (r.record != null) {
- final long origId = Binder.clearCallingIdentity();
+ final long origId = mAm.mInjector.clearCallingIdentity();
try {
stopServiceLocked(r.record, false);
} finally {
- Binder.restoreCallingIdentity(origId);
+ mAm.mInjector.restoreCallingIdentity(origId);
}
return 1;
}
@@ -1649,7 +1702,7 @@
IBinder peekServiceLocked(Intent service, String resolvedType, String callingPackage) {
ServiceLookupResult r = retrieveServiceLocked(service, null, resolvedType, callingPackage,
- Binder.getCallingPid(), Binder.getCallingUid(),
+ mAm.mInjector.getCallingPid(), mAm.mInjector.getCallingUid(),
UserHandle.getCallingUserId(), false, false, false, false, false, false);
IBinder ret = null;
@@ -1658,8 +1711,8 @@
if (r.record == null) {
throw new SecurityException(
"Permission Denial: Accessing service"
- + " from pid=" + Binder.getCallingPid()
- + ", uid=" + Binder.getCallingUid()
+ + " from pid=" + mAm.mInjector.getCallingPid()
+ + ", uid=" + mAm.mInjector.getCallingUid()
+ " requires " + r.permission);
}
IntentBindRecord ib = r.record.bindings.get(r.record.intent);
@@ -1719,9 +1772,9 @@
}
}
r.callStart = false;
- final long origId = Binder.clearCallingIdentity();
+ final long origId = mAm.mInjector.clearCallingIdentity();
bringDownServiceIfNeededLocked(r, false, false, false, "stopServiceToken");
- Binder.restoreCallingIdentity(origId);
+ mAm.mInjector.restoreCallingIdentity(origId);
return true;
}
return false;
@@ -1734,14 +1787,14 @@
public void setServiceForegroundLocked(ComponentName className, IBinder token,
int id, Notification notification, int flags, int foregroundServiceType) {
final int userId = UserHandle.getCallingUserId();
- final long origId = Binder.clearCallingIdentity();
+ final long origId = mAm.mInjector.clearCallingIdentity();
try {
ServiceRecord r = findServiceLocked(className, token, userId);
if (r != null) {
setServiceForegroundInnerLocked(r, id, notification, flags, foregroundServiceType);
}
} finally {
- Binder.restoreCallingIdentity(origId);
+ mAm.mInjector.restoreCallingIdentity(origId);
}
}
@@ -1753,7 +1806,7 @@
*/
public int getForegroundServiceTypeLocked(ComponentName className, IBinder token) {
final int userId = UserHandle.getCallingUserId();
- final long origId = Binder.clearCallingIdentity();
+ final long origId = mAm.mInjector.clearCallingIdentity();
int ret = ServiceInfo.FOREGROUND_SERVICE_TYPE_NONE;
try {
ServiceRecord r = findServiceLocked(className, token, userId);
@@ -1761,7 +1814,7 @@
ret = r.foregroundServiceType;
}
} finally {
- Binder.restoreCallingIdentity(origId);
+ mAm.mInjector.restoreCallingIdentity(origId);
}
return ret;
}
@@ -3483,7 +3536,7 @@
boolean shouldServiceTimeOutLocked(ComponentName className, IBinder token) {
final int userId = UserHandle.getCallingUserId();
- final long ident = Binder.clearCallingIdentity();
+ final long ident = mAm.mInjector.clearCallingIdentity();
try {
ServiceRecord sr = findServiceLocked(className, token, userId);
if (sr == null) {
@@ -3492,7 +3545,7 @@
final long nowUptime = SystemClock.uptimeMillis();
return sr.shouldTriggerShortFgsTimeout(nowUptime);
} finally {
- Binder.restoreCallingIdentity(ident);
+ mAm.mInjector.restoreCallingIdentity(ident);
}
}
@@ -3636,8 +3689,8 @@
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "bindService: " + service
+ " type=" + resolvedType + " conn=" + connection.asBinder()
+ " flags=0x" + Long.toHexString(flags));
- final int callingPid = Binder.getCallingPid();
- final int callingUid = Binder.getCallingUid();
+ final int callingPid = mAm.mInjector.getCallingPid();
+ final int callingUid = mAm.mInjector.getCallingUid();
final ProcessRecord callerApp = mAm.getRecordForAppLOSP(caller);
if (callerApp == null) {
throw new SecurityException(
@@ -3778,7 +3831,7 @@
&& !requestStartTargetPermissionsReviewIfNeededLocked(s, callingPackage, null,
callingUid, service, callerFg, userId, true, connection);
- final long origId = Binder.clearCallingIdentity();
+ final long origId = mAm.mInjector.clearCallingIdentity();
try {
if (unscheduleServiceRestartLocked(s, callerApp.info.uid, false)) {
@@ -3859,12 +3912,34 @@
}
clist.add(c);
+ final boolean isolated = (s.serviceInfo.flags & ServiceInfo.FLAG_ISOLATED_PROCESS) != 0;
+ final ProcessRecord hostApp = isolated
+ ? null
+ : mAm.getProcessRecordLocked(s.processName, s.appInfo.uid);
+ final int serviceBindingOomAdjPolicy = hostApp != null
+ ? getServiceBindingOomAdjPolicyForAddLocked(b.client, hostApp, c)
+ : SERVICE_BIND_OOMADJ_POLICY_LEGACY;
+
+ final boolean shouldFreezeCaller = !packageFrozen && !permissionsReviewRequired
+ && (serviceBindingOomAdjPolicy & SERVICE_BIND_OOMADJ_POLICY_FREEZE_CALLER) != 0
+ && callerApp.isFreezable();
+
+ if (shouldFreezeCaller) {
+ // Freeze the caller immediately, so the following #onBind/#onConnected will be
+ // queued up in the app side as they're one way calls. And we'll also hold off
+ // the service timeout timer until the process is unfrozen.
+ mAm.mOomAdjuster.updateAppFreezeStateLSP(callerApp, OOM_ADJ_REASON_BIND_SERVICE,
+ true);
+ }
+
boolean needOomAdj = false;
if (c.hasFlag(Context.BIND_AUTO_CREATE)) {
s.lastActivity = SystemClock.uptimeMillis();
- needOomAdj = true;
+ needOomAdj = (serviceBindingOomAdjPolicy
+ & SERVICE_BIND_OOMADJ_POLICY_SKIP_OOM_UPDATE_ON_CREATE) == 0;
if (bringUpServiceLocked(s, service.getFlags(), callerFg, false,
- permissionsReviewRequired, packageFrozen, true) != null) {
+ permissionsReviewRequired, packageFrozen, true, serviceBindingOomAdjPolicy)
+ != null) {
mAm.updateOomAdjPendingTargetsLocked(OOM_ADJ_REASON_BIND_SERVICE);
return 0;
}
@@ -3886,8 +3961,11 @@
|| (callerApp.mState.getCurProcState() <= PROCESS_STATE_TOP
&& c.hasFlag(Context.BIND_TREAT_LIKE_ACTIVITY)),
b.client);
- needOomAdj = true;
- mAm.enqueueOomAdjTargetLocked(s.app);
+ if ((serviceBindingOomAdjPolicy
+ & SERVICE_BIND_OOMADJ_POLICY_SKIP_OOM_UPDATE_ON_CONNECT) == 0) {
+ needOomAdj = true;
+ mAm.enqueueOomAdjTargetLocked(s.app);
+ }
}
if (needOomAdj) {
mAm.updateOomAdjPendingTargetsLocked(OOM_ADJ_REASON_BIND_SERVICE);
@@ -3937,10 +4015,12 @@
// and the service had previously asked to be told when
// rebound, then do so.
if (b.intent.apps.size() == 1 && b.intent.doRebind) {
- requestServiceBindingLocked(s, b.intent, callerFg, true);
+ requestServiceBindingLocked(s, b.intent, callerFg, true,
+ serviceBindingOomAdjPolicy);
}
} else if (!b.intent.requested) {
- requestServiceBindingLocked(s, b.intent, callerFg, false);
+ requestServiceBindingLocked(s, b.intent, callerFg, false,
+ serviceBindingOomAdjPolicy);
}
maybeLogBindCrossProfileService(userId, callingPackage, callerApp.info.uid);
@@ -3948,7 +4028,7 @@
getServiceMapLocked(s.userId).ensureNotStartingBackgroundLocked(s);
} finally {
- Binder.restoreCallingIdentity(origId);
+ mAm.mInjector.restoreCallingIdentity(origId);
}
notifyBindingServiceEventLocked(callerApp, callingPackage);
@@ -3982,7 +4062,7 @@
}
void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {
- final long origId = Binder.clearCallingIdentity();
+ final long origId = mAm.mInjector.clearCallingIdentity();
try {
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "PUBLISHING " + r
+ " " + intent + ": " + service);
@@ -4025,10 +4105,11 @@
}
serviceDoneExecutingLocked(r, mDestroyingServices.contains(r), false, false,
- OOM_ADJ_REASON_EXECUTING_SERVICE);
+ !Flags.serviceBindingOomAdjPolicy() || b == null || !b.mSkippedOomAdj
+ ? OOM_ADJ_REASON_EXECUTING_SERVICE : OOM_ADJ_REASON_NONE);
}
} finally {
- Binder.restoreCallingIdentity(origId);
+ mAm.mInjector.restoreCallingIdentity(origId);
}
}
@@ -4078,8 +4159,8 @@
return false;
}
- final int callingPid = Binder.getCallingPid();
- final long origId = Binder.clearCallingIdentity();
+ final int callingPid = mAm.mInjector.getCallingPid();
+ final long origId = mAm.mInjector.clearCallingIdentity();
try {
if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
String info;
@@ -4092,9 +4173,10 @@
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "unbindServiceLocked: " + info);
}
+ boolean needOomAdj = false;
while (clist.size() > 0) {
ConnectionRecord r = clist.get(0);
- removeConnectionLocked(r, null, null, true);
+ int serviceBindingOomAdjPolicy = removeConnectionLocked(r, null, null, true);
if (clist.size() > 0 && clist.get(0) == r) {
// In case it didn't get removed above, do it now.
Slog.wtf(TAG, "Connection " + r + " not removed for binder " + binder);
@@ -4112,22 +4194,28 @@
psr.setTreatLikeActivity(true);
mAm.updateLruProcessLocked(app, true, null);
}
- mAm.enqueueOomAdjTargetLocked(app);
+ // If the bindee is more important than the binder, we may skip the OomAdjuster.
+ if (serviceBindingOomAdjPolicy == SERVICE_BIND_OOMADJ_POLICY_LEGACY) {
+ mAm.enqueueOomAdjTargetLocked(app);
+ needOomAdj = true;
+ }
}
}
- mAm.updateOomAdjPendingTargetsLocked(OOM_ADJ_REASON_UNBIND_SERVICE);
+ if (needOomAdj) {
+ mAm.updateOomAdjPendingTargetsLocked(OOM_ADJ_REASON_UNBIND_SERVICE);
+ }
} finally {
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
- Binder.restoreCallingIdentity(origId);
+ mAm.mInjector.restoreCallingIdentity(origId);
}
return true;
}
void unbindFinishedLocked(ServiceRecord r, Intent intent, boolean doRebind) {
- final long origId = Binder.clearCallingIdentity();
+ final long origId = mAm.mInjector.clearCallingIdentity();
try {
if (r != null) {
Intent.FilterComparison filter
@@ -4138,6 +4226,7 @@
+ (b != null ? b.apps.size() : 0));
boolean inDestroying = mDestroyingServices.contains(r);
+ boolean skipOomAdj = false;
if (b != null) {
if (b.apps.size() > 0 && !inDestroying) {
// Applications have already bound since the last
@@ -4152,7 +4241,8 @@
}
}
try {
- requestServiceBindingLocked(r, b, inFg, true);
+ requestServiceBindingLocked(r, b, inFg, true,
+ SERVICE_BIND_OOMADJ_POLICY_LEGACY);
} catch (TransactionTooLargeException e) {
// Don't pass this back to ActivityThread, it's unrelated.
}
@@ -4161,13 +4251,14 @@
// a new client.
b.doRebind = true;
}
+ skipOomAdj = Flags.serviceBindingOomAdjPolicy() && b.mSkippedOomAdj;
}
serviceDoneExecutingLocked(r, inDestroying, false, false,
- OOM_ADJ_REASON_UNBIND_SERVICE);
+ skipOomAdj ? OOM_ADJ_REASON_NONE : OOM_ADJ_REASON_UNBIND_SERVICE);
}
} finally {
- Binder.restoreCallingIdentity(origId);
+ mAm.mInjector.restoreCallingIdentity(origId);
}
}
@@ -4503,7 +4594,7 @@
userId = 0;
smap = getServiceMapLocked(0);
// Bypass INTERACT_ACROSS_USERS permission check
- final long token = Binder.clearCallingIdentity();
+ final long token = mAm.mInjector.clearCallingIdentity();
try {
ResolveInfo rInfoForUserId0 =
mAm.getPackageManagerInternal().resolveService(service,
@@ -4516,7 +4607,7 @@
}
sInfo = rInfoForUserId0.serviceInfo;
} finally {
- Binder.restoreCallingIdentity(token);
+ mAm.mInjector.restoreCallingIdentity(token);
}
}
sInfo = new ServiceInfo(sInfo);
@@ -4645,7 +4736,8 @@
* @return {@code true} if it performed oomAdjUpdate.
*/
private boolean bumpServiceExecutingLocked(
- ServiceRecord r, boolean fg, String why, @OomAdjReason int oomAdjReason) {
+ ServiceRecord r, boolean fg, String why, @OomAdjReason int oomAdjReason,
+ boolean skipTimeoutIfPossible) {
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, ">>> EXECUTING "
+ why + " of " + r + " in app " + r.app);
else if (DEBUG_SERVICE_EXECUTING) Slog.v(TAG_SERVICE_EXECUTING, ">>> EXECUTING "
@@ -4669,6 +4761,10 @@
timeoutNeeded = false;
}
+ // If the process is frozen or to be frozen, and we want to skip the timeout, skip it.
+ final boolean shouldSkipTimeout = skipTimeoutIfPossible && r.app != null
+ && (r.app.mOptRecord.isPendingFreeze() || r.app.mOptRecord.isFrozen());
+
ProcessServiceRecord psr;
if (r.executeNesting == 0) {
r.executeFg = fg;
@@ -4684,7 +4780,11 @@
psr.startExecutingService(r);
psr.setExecServicesFg(psr.shouldExecServicesFg() || fg);
if (timeoutNeeded && psr.numberOfExecutingServices() == 1) {
- scheduleServiceTimeoutLocked(r.app);
+ if (!shouldSkipTimeout) {
+ scheduleServiceTimeoutLocked(r.app);
+ } else {
+ r.app.mServices.noteScheduleServiceTimeoutPending(true);
+ }
}
}
} else if (r.app != null && fg) {
@@ -4692,7 +4792,11 @@
if (!psr.shouldExecServicesFg()) {
psr.setExecServicesFg(true);
if (timeoutNeeded) {
- scheduleServiceTimeoutLocked(r.app);
+ if (!shouldSkipTimeout) {
+ scheduleServiceTimeoutLocked(r.app);
+ } else {
+ r.app.mServices.noteScheduleServiceTimeoutPending(true);
+ }
}
}
}
@@ -4712,16 +4816,22 @@
}
private final boolean requestServiceBindingLocked(ServiceRecord r, IntentBindRecord i,
- boolean execInFg, boolean rebind) throws TransactionTooLargeException {
+ boolean execInFg, boolean rebind,
+ @ServiceBindingOomAdjPolicy int serviceBindingOomAdjPolicy)
+ throws TransactionTooLargeException {
if (r.app == null || r.app.getThread() == null) {
// If service is not currently running, can't yet bind.
return false;
}
if (DEBUG_SERVICE) Slog.d(TAG_SERVICE, "requestBind " + i + ": requested=" + i.requested
+ " rebind=" + rebind);
+ final boolean skipOomAdj = (serviceBindingOomAdjPolicy
+ & SERVICE_BIND_OOMADJ_POLICY_SKIP_OOM_UPDATE_ON_BIND) != 0;
if ((!i.requested || rebind) && i.apps.size() > 0) {
try {
- bumpServiceExecutingLocked(r, execInFg, "bind", OOM_ADJ_REASON_BIND_SERVICE);
+ i.mSkippedOomAdj = !bumpServiceExecutingLocked(r, execInFg, "bind",
+ skipOomAdj ? OOM_ADJ_REASON_NONE : OOM_ADJ_REASON_BIND_SERVICE,
+ skipOomAdj /* skipTimeoutIfPossible */);
if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
Trace.instant(Trace.TRACE_TAG_ACTIVITY_MANAGER, "requestServiceBinding="
+ i.intent.getIntent() + ". bindSeq=" + mBindServiceSeqCounter);
@@ -4738,14 +4848,14 @@
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Crashed while binding " + r, e);
final boolean inDestroying = mDestroyingServices.contains(r);
serviceDoneExecutingLocked(r, inDestroying, inDestroying, false,
- OOM_ADJ_REASON_UNBIND_SERVICE);
+ skipOomAdj ? OOM_ADJ_REASON_NONE : OOM_ADJ_REASON_UNBIND_SERVICE);
throw e;
} catch (RemoteException e) {
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Crashed while binding " + r);
// Keep the executeNesting count accurate.
final boolean inDestroying = mDestroyingServices.contains(r);
serviceDoneExecutingLocked(r, inDestroying, inDestroying, false,
- OOM_ADJ_REASON_UNBIND_SERVICE);
+ skipOomAdj ? OOM_ADJ_REASON_NONE : OOM_ADJ_REASON_UNBIND_SERVICE);
return false;
}
}
@@ -5117,7 +5227,7 @@
}
try {
bringUpServiceLocked(r, r.intent.getIntent().getFlags(), r.createdFromFg, true, false,
- false, true);
+ false, true, SERVICE_BIND_OOMADJ_POLICY_LEGACY);
} catch (TransactionTooLargeException e) {
// Ignore, it's been logged and nothing upstack cares.
} finally {
@@ -5217,7 +5327,7 @@
private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
boolean whileRestarting, boolean permissionsReviewRequired, boolean packageFrozen,
- boolean enqueueOomAdj)
+ boolean enqueueOomAdj, @ServiceBindingOomAdjPolicy int serviceBindingOomAdjPolicy)
throws TransactionTooLargeException {
try {
if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
@@ -5225,7 +5335,8 @@
"bringUpServiceLocked: " + r.shortInstanceName);
}
return bringUpServiceInnerLocked(r, intentFlags, execInFg, whileRestarting,
- permissionsReviewRequired, packageFrozen, enqueueOomAdj);
+ permissionsReviewRequired, packageFrozen, enqueueOomAdj,
+ serviceBindingOomAdjPolicy);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
}
@@ -5233,7 +5344,7 @@
private String bringUpServiceInnerLocked(ServiceRecord r, int intentFlags, boolean execInFg,
boolean whileRestarting, boolean permissionsReviewRequired, boolean packageFrozen,
- boolean enqueueOomAdj)
+ boolean enqueueOomAdj, @ServiceBindingOomAdjPolicy int serviceBindingOomAdjPolicy)
throws TransactionTooLargeException {
if (r.app != null && r.app.isThreadReady()) {
sendServiceArgsLocked(r, execInFg, false);
@@ -5317,7 +5428,7 @@
app.addPackage(r.appInfo.packageName, r.appInfo.longVersionCode,
mAm.mProcessStats);
realStartServiceLocked(r, app, thread, pid, uidRecord, execInFg,
- enqueueOomAdj);
+ enqueueOomAdj, serviceBindingOomAdjPolicy);
return null;
} catch (TransactionTooLargeException e) {
throw e;
@@ -5347,7 +5458,7 @@
"realStartServiceLocked: " + r.shortInstanceName);
}
realStartServiceLocked(r, app, thread, pid, uidRecord, execInFg,
- enqueueOomAdj);
+ enqueueOomAdj, SERVICE_BIND_OOMADJ_POLICY_LEGACY);
return null;
} catch (TransactionTooLargeException e) {
throw e;
@@ -5452,16 +5563,61 @@
return HostingRecord.TRIGGER_TYPE_UNKNOWN;
}
- private final void requestServiceBindingsLocked(ServiceRecord r, boolean execInFg)
+ private void requestServiceBindingsLocked(ServiceRecord r, boolean execInFg,
+ @ServiceBindingOomAdjPolicy int serviceBindingOomAdjPolicy)
throws TransactionTooLargeException {
for (int i=r.bindings.size()-1; i>=0; i--) {
IntentBindRecord ibr = r.bindings.valueAt(i);
- if (!requestServiceBindingLocked(r, ibr, execInFg, false)) {
+ if (!requestServiceBindingLocked(r, ibr, execInFg, false, serviceBindingOomAdjPolicy)) {
break;
}
}
}
+ @ServiceBindingOomAdjPolicy
+ private int getServiceBindingOomAdjPolicyForAddLocked(ProcessRecord clientApp,
+ ProcessRecord hostApp, ConnectionRecord cr) {
+ @ServiceBindingOomAdjPolicy int policy = SERVICE_BIND_OOMADJ_POLICY_LEGACY;
+ if (Flags.serviceBindingOomAdjPolicy() && clientApp != null && hostApp != null) {
+ if (clientApp == hostApp) {
+ policy = DEFAULT_SERVICE_NO_BUMP_BIND_POLICY_FLAG;
+ } else if (clientApp.isCached()) {
+ policy = DEFAULT_SERVICE_NO_BUMP_BIND_POLICY_FLAG;
+ if (clientApp.isFreezable()) {
+ policy |= SERVICE_BIND_OOMADJ_POLICY_FREEZE_CALLER;
+ }
+ }
+ if ((policy & SERVICE_BIND_OOMADJ_POLICY_SKIP_OOM_UPDATE_ON_CONNECT) == 0) {
+ // Binding between two different processes.
+ // Check if the caller has a better process state, oom adj score,
+ // or if the caller has more capabilities.
+ if (!mAm.mOomAdjuster.evaluateServiceConnectionAdd(clientApp, hostApp, cr)) {
+ // Running an oom adjuster won't be give the host app a better score, skip it.
+ policy = DEFAULT_SERVICE_NO_BUMP_BIND_POLICY_FLAG;
+ }
+ }
+ }
+ return policy;
+ }
+
+ @ServiceBindingOomAdjPolicy
+ private int getServiceBindingOomAdjPolicyForRemovalLocked(ProcessRecord clientApp,
+ ProcessRecord hostApp, ConnectionRecord cr) {
+ @ServiceBindingOomAdjPolicy int policy = SERVICE_BIND_OOMADJ_POLICY_LEGACY;
+ if (Flags.serviceBindingOomAdjPolicy() && clientApp != null && hostApp != null
+ && cr != null) {
+ if (clientApp == hostApp) {
+ policy = DEFAULT_SERVICE_NO_BUMP_BIND_POLICY_FLAG;
+ } else {
+ if (!mAm.mOomAdjuster.evaluateServiceConnectionRemoval(clientApp, hostApp, cr)) {
+ // Running an oom adjuster won't be give the host app a better score, skip it.
+ policy = DEFAULT_SERVICE_NO_BUMP_BIND_POLICY_FLAG;
+ }
+ }
+ }
+ return policy;
+ }
+
/**
* Note the name of this method should not be confused with the started services concept.
* The "start" here means bring up the instance in the client, and this method is called
@@ -5469,7 +5625,8 @@
*/
private void realStartServiceLocked(ServiceRecord r, ProcessRecord app,
IApplicationThread thread, int pid, UidRecord uidRecord, boolean execInFg,
- boolean enqueueOomAdj) throws RemoteException {
+ boolean enqueueOomAdj, @ServiceBindingOomAdjPolicy int serviceBindingOomAdjPolicy)
+ throws RemoteException {
if (thread == null) {
throw new RemoteException();
}
@@ -5478,17 +5635,28 @@
+ ", ProcessRecord.uid = " + app.uid);
r.setProcess(app, thread, pid, uidRecord);
r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
-
+ final boolean skipOomAdj = (serviceBindingOomAdjPolicy
+ & SERVICE_BIND_OOMADJ_POLICY_SKIP_OOM_UPDATE_ON_CREATE) != 0;
final ProcessServiceRecord psr = app.mServices;
final boolean newService = psr.startService(r);
bumpServiceExecutingLocked(r, execInFg, "create",
- OOM_ADJ_REASON_NONE /* use "none" to avoid extra oom adj */);
+ OOM_ADJ_REASON_NONE /* use "none" to avoid extra oom adj */,
+ skipOomAdj /* skipTimeoutIfPossible */);
mAm.updateLruProcessLocked(app, false, null);
updateServiceForegroundLocked(psr, /* oomAdj= */ false);
- // Force an immediate oomAdjUpdate, so the client app could be in the correct process state
- // before doing any service related transactions
- mAm.enqueueOomAdjTargetLocked(app);
- mAm.updateOomAdjPendingTargetsLocked(OOM_ADJ_REASON_START_SERVICE);
+ // Skip the oom adj update if it's a self-binding, the Service#onCreate() will be running
+ // at its current adj score.
+ if (!skipOomAdj) {
+ // Force an immediate oomAdjUpdate, so the host app could be in the correct
+ // process state before doing any service related transactions
+ mAm.enqueueOomAdjTargetLocked(app);
+ mAm.updateOomAdjPendingTargetsLocked(OOM_ADJ_REASON_START_SERVICE);
+ } else {
+ // Since we skipped the oom adj update, the Service#onCreate() might be running in
+ // the cached state, if the service process drops into the cached state after the call.
+ // But there is still a grace period before freezing it, so we should be fine
+ // in terms of not getting an ANR.
+ }
boolean created = false;
try {
@@ -5523,7 +5691,7 @@
// Keep the executeNesting count accurate.
final boolean inDestroying = mDestroyingServices.contains(r);
serviceDoneExecutingLocked(r, inDestroying, inDestroying, false,
- OOM_ADJ_REASON_STOP_SERVICE);
+ skipOomAdj ? OOM_ADJ_REASON_NONE : OOM_ADJ_REASON_STOP_SERVICE);
// Cleanup.
if (newService) {
@@ -5542,7 +5710,7 @@
psr.mAllowlistManager = true;
}
- requestServiceBindingsLocked(r, execInFg);
+ requestServiceBindingsLocked(r, execInFg, serviceBindingOomAdjPolicy);
updateServiceClientActivitiesLocked(psr, null, true);
@@ -5610,7 +5778,8 @@
UserHandle.getAppId(r.appInfo.uid)
);
bumpServiceExecutingLocked(r, execInFg, "start",
- OOM_ADJ_REASON_NONE /* use "none" to avoid extra oom adj */);
+ OOM_ADJ_REASON_NONE /* use "none" to avoid extra oom adj */,
+ false /* skipTimeoutIfPossible */);
if (r.fgRequired && !r.fgWaiting) {
if (!r.isForeground) {
if (DEBUG_BACKGROUND_CHECK) {
@@ -5753,7 +5922,8 @@
if (ibr.hasBound) {
try {
oomAdjusted |= bumpServiceExecutingLocked(r, false, "bring down unbind",
- OOM_ADJ_REASON_UNBIND_SERVICE);
+ OOM_ADJ_REASON_UNBIND_SERVICE,
+ false /* skipTimeoutIfPossible */);
ibr.hasBound = false;
ibr.requested = false;
r.app.getThread().scheduleUnbindService(r,
@@ -5909,7 +6079,8 @@
} else {
try {
oomAdjusted |= bumpServiceExecutingLocked(r, false, "destroy",
- oomAdjusted ? 0 : OOM_ADJ_REASON_STOP_SERVICE);
+ oomAdjusted ? 0 : OOM_ADJ_REASON_STOP_SERVICE,
+ false /* skipTimeoutIfPossible */);
mDestroyingServices.add(r);
r.destroying = true;
r.app.getThread().scheduleStopService(r);
@@ -5992,11 +6163,17 @@
}
}
- void removeConnectionLocked(ConnectionRecord c, ProcessRecord skipApp,
+ /**
+ * @return The ServiceBindingOomAdjPolicy used in this removal.
+ */
+ @ServiceBindingOomAdjPolicy
+ int removeConnectionLocked(ConnectionRecord c, ProcessRecord skipApp,
ActivityServiceConnectionsHolder skipAct, boolean enqueueOomAdj) {
IBinder binder = c.conn.asBinder();
AppBindRecord b = c.binding;
ServiceRecord s = b.service;
+ @ServiceBindingOomAdjPolicy int serviceBindingOomAdjPolicy =
+ SERVICE_BIND_OOMADJ_POLICY_LEGACY;
ArrayList<ConnectionRecord> clist = s.getConnections().get(binder);
if (clist != null) {
clist.remove(c);
@@ -6055,8 +6232,14 @@
+ ": shouldUnbind=" + b.intent.hasBound);
if (s.app != null && s.app.isThreadReady() && b.intent.apps.size() == 0
&& b.intent.hasBound) {
+ serviceBindingOomAdjPolicy = getServiceBindingOomAdjPolicyForRemovalLocked(b.client,
+ s.app, c);
+ final boolean skipOomAdj = (serviceBindingOomAdjPolicy
+ & SERVICE_BIND_OOMADJ_POLICY_SKIP_OOM_UPDATE_ON_CONNECT) != 0;
try {
- bumpServiceExecutingLocked(s, false, "unbind", OOM_ADJ_REASON_UNBIND_SERVICE);
+ b.intent.mSkippedOomAdj = !bumpServiceExecutingLocked(s, false, "unbind",
+ skipOomAdj ? OOM_ADJ_REASON_NONE : OOM_ADJ_REASON_UNBIND_SERVICE,
+ skipOomAdj /* skipTimeoutIfPossible */);
if (b.client != s.app && c.notHasFlag(Context.BIND_WAIVE_PRIORITY)
&& s.app.mState.getSetProcState() <= PROCESS_STATE_HEAVY_WEIGHT) {
// If this service's process is not already in the cached list,
@@ -6096,12 +6279,14 @@
"removeConnection");
}
}
+ return serviceBindingOomAdjPolicy;
}
void serviceDoneExecutingLocked(ServiceRecord r, int type, int startId, int res,
- boolean enqueueOomAdj) {
+ boolean enqueueOomAdj, Intent intent) {
boolean inDestroying = mDestroyingServices.contains(r);
if (r != null) {
+ boolean skipOomAdj = false;
if (type == ActivityThread.SERVICE_DONE_EXECUTING_START) {
// This is a call from a service start... take care of
// book-keeping.
@@ -6177,14 +6362,19 @@
// Fake it to keep from ANR due to orphaned entry.
r.executeNesting = 1;
}
+ } else if (type == ActivityThread.SERVICE_DONE_EXECUTING_REBIND
+ || type == ActivityThread.SERVICE_DONE_EXECUTING_UNBIND) {
+ final Intent.FilterComparison filter = new Intent.FilterComparison(intent);
+ final IntentBindRecord b = r.bindings.get(filter);
+ skipOomAdj = Flags.serviceBindingOomAdjPolicy() && b != null && b.mSkippedOomAdj;
}
- final long origId = Binder.clearCallingIdentity();
+ final long origId = mAm.mInjector.clearCallingIdentity();
serviceDoneExecutingLocked(r, inDestroying, inDestroying, enqueueOomAdj,
- OOM_ADJ_REASON_EXECUTING_SERVICE);
- Binder.restoreCallingIdentity(origId);
+ skipOomAdj ? OOM_ADJ_REASON_NONE : OOM_ADJ_REASON_EXECUTING_SERVICE);
+ mAm.mInjector.restoreCallingIdentity(origId);
} else {
Slog.w(TAG, "Done executing unknown service from pid "
- + Binder.getCallingPid());
+ + mAm.mInjector.getCallingPid());
}
}
@@ -6236,10 +6426,17 @@
mDestroyingServices.remove(r);
r.bindings.clear();
}
- if (enqueueOomAdj) {
- mAm.enqueueOomAdjTargetLocked(r.app);
+ boolean oomAdjusted = false;
+ if (oomAdjReason != OOM_ADJ_REASON_NONE) {
+ if (enqueueOomAdj) {
+ mAm.enqueueOomAdjTargetLocked(r.app);
+ } else {
+ mAm.updateOomAdjLocked(r.app, oomAdjReason);
+ }
+ oomAdjusted = true;
} else {
- mAm.updateOomAdjLocked(r.app, oomAdjReason);
+ // Skip oom adj if it wasn't bumped during the bumpServiceExecutingLocked()
+ oomAdjusted = false;
}
}
r.executeFg = false;
@@ -6296,7 +6493,7 @@
"realStartServiceLocked: " + sr.shortInstanceName);
}
realStartServiceLocked(sr, proc, thread, pid, uidRecord, sr.createdFromFg,
- true);
+ true, SERVICE_BIND_OOMADJ_POLICY_LEGACY);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
}
@@ -6786,6 +6983,7 @@
}
psr.stopAllExecutingServices();
+ psr.noteScheduleServiceTimeoutPending(false);
}
ActivityManager.RunningServiceInfo makeRunningServiceInfoLocked(ServiceRecord r) {
@@ -6836,7 +7034,7 @@
ArrayList<ActivityManager.RunningServiceInfo> res
= new ArrayList<ActivityManager.RunningServiceInfo>();
- final long ident = Binder.clearCallingIdentity();
+ final long ident = mAm.mInjector.clearCallingIdentity();
try {
if (canInteractAcrossUsers) {
int[] users = mAm.mUserController.getUsers();
@@ -6878,14 +7076,14 @@
}
}
} finally {
- Binder.restoreCallingIdentity(ident);
+ mAm.mInjector.restoreCallingIdentity(ident);
}
return res;
}
public PendingIntent getRunningServiceControlPanelLocked(ComponentName name) {
- int userId = UserHandle.getUserId(Binder.getCallingUid());
+ int userId = UserHandle.getUserId(mAm.mInjector.getCallingUid());
ServiceRecord r = getServiceByNameLocked(name, userId);
if (r != null) {
ArrayMap<IBinder, ArrayList<ConnectionRecord>> connections = r.getConnections();
@@ -7077,6 +7275,7 @@
final long delay = proc.mServices.shouldExecServicesFg()
? mAm.mConstants.SERVICE_TIMEOUT : mAm.mConstants.SERVICE_BACKGROUND_TIMEOUT;
mActiveServiceAnrTimer.start(proc, delay);
+ proc.mServices.noteScheduleServiceTimeoutPending(false);
}
void scheduleServiceForegroundTransitionTimeoutLocked(ServiceRecord r) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index ca04e41..374a17a 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -135,6 +135,7 @@
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONFIGURATION;
import static com.android.internal.util.FrameworkStatsLog.UNSAFE_INTENT_EVENT_REPORTED__EVENT_TYPE__INTERNAL_NON_EXPORTED_COMPONENT_MATCH;
import static com.android.internal.util.FrameworkStatsLog.UNSAFE_INTENT_EVENT_REPORTED__EVENT_TYPE__NEW_MUTABLE_IMPLICIT_PENDING_INTENT_RETRIEVED;
+import static com.android.sdksandbox.flags.Flags.sdkSandboxInstrumentationInfo;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ALL;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ALLOWLISTS;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BACKGROUND_CHECK;
@@ -1751,7 +1752,7 @@
@GuardedBy("mProcLock")
private long mLastBinderHeavyHitterAutoSamplerStart = 0L;
- final AppProfiler mAppProfiler;
+ AppProfiler mAppProfiler;
private static final int INDEX_NATIVE_PSS = 0;
private static final int INDEX_NATIVE_SWAP_PSS = 1;
@@ -2496,7 +2497,7 @@
mInjector = injector;
mContext = mInjector.getContext();
mUiContext = null;
- mAppErrors = null;
+ mAppErrors = injector.getAppErrors();
mPackageWatchdog = null;
mAppOpsService = mInjector.getAppOpsService(null /* recentAccessesFile */,
null /* storageFile */, null /* handler */);
@@ -2514,7 +2515,7 @@
? new OomAdjusterModernImpl(this, mProcessList, activeUids, handlerThread)
: new OomAdjuster(this, mProcessList, activeUids, handlerThread);
- mIntentFirewall = null;
+ mIntentFirewall = injector.getIntentFirewall();
mProcessStats = new ProcessStatsService(this, mContext.getCacheDir());
mCpHelper = new ContentProviderHelper(this, false);
mServices = mInjector.getActiveServices(this);
@@ -13889,13 +13890,15 @@
}
}
- public void serviceDoneExecuting(IBinder token, int type, int startId, int res) {
+ @Override
+ public void serviceDoneExecuting(IBinder token, int type, int startId, int res, Intent intent) {
synchronized(this) {
if (!(token instanceof ServiceRecord)) {
Slog.e(TAG, "serviceDoneExecuting: Invalid service token=" + token);
throw new IllegalArgumentException("Invalid service token");
}
- mServices.serviceDoneExecutingLocked((ServiceRecord) token, type, startId, res, false);
+ mServices.serviceDoneExecutingLocked((ServiceRecord) token, type, startId, res, false,
+ intent);
}
}
@@ -16139,10 +16142,22 @@
}
final ApplicationInfo sdkSandboxInfo;
+ final String processName;
try {
- sdkSandboxInfo =
- sandboxManagerLocal.getSdkSandboxApplicationInfoForInstrumentation(
- sdkSandboxClientAppInfo, isSdkInSandbox);
+ if (sdkSandboxInstrumentationInfo()) {
+ sdkSandboxInfo =
+ sandboxManagerLocal.getSdkSandboxApplicationInfoForInstrumentation(
+ sdkSandboxClientAppInfo, isSdkInSandbox);
+ processName = sdkSandboxInfo.processName;
+ } else {
+ final PackageManager pm = mContext.getPackageManager();
+ sdkSandboxInfo =
+ pm.getApplicationInfoAsUser(pm.getSdkSandboxPackageName(), 0, userId);
+ processName =
+ sandboxManagerLocal.getSdkSandboxProcessNameForInstrumentation(
+ sdkSandboxClientAppInfo);
+ sdkSandboxInfo.uid = Process.toSdkSandboxUid(sdkSandboxClientAppInfo.uid);
+ }
} catch (NameNotFoundException e) {
reportStartInstrumentationFailureLocked(
watcher, className, "Can't find SdkSandbox package");
@@ -16151,7 +16166,7 @@
ActiveInstrumentation activeInstr = new ActiveInstrumentation(this);
activeInstr.mClass = className;
- activeInstr.mTargetProcesses = new String[]{sdkSandboxInfo.processName};
+ activeInstr.mTargetProcesses = new String[]{processName};
activeInstr.mTargetInfo = sdkSandboxInfo;
activeInstr.mIsSdkInSandbox = isSdkInSandbox;
activeInstr.mProfileFile = profileFile;
@@ -16194,7 +16209,7 @@
ProcessRecord app = addAppLocked(
sdkSandboxInfo,
- sdkSandboxInfo.processName,
+ processName,
/* isolated= */ false,
/* isSdkSandbox= */ true,
sdkSandboxInfo.uid,
@@ -20236,6 +20251,36 @@
}
return broadcastQueues;
}
+
+ /** @see Binder#getCallingUid */
+ public int getCallingUid() {
+ return Binder.getCallingUid();
+ }
+
+ /** @see Binder#getCallingPid */
+ public int getCallingPid() {
+ return Binder.getCallingUid();
+ }
+
+ /** @see Binder#clearCallingIdentity */
+ public long clearCallingIdentity() {
+ return Binder.clearCallingIdentity();
+ }
+
+ /** @see Binder#clearCallingIdentity */
+ public void restoreCallingIdentity(long ident) {
+ Binder.restoreCallingIdentity(ident);
+ }
+
+ /** @return the default instance of AppErrors */
+ public AppErrors getAppErrors() {
+ return null;
+ }
+
+ /** @return the default instance of intent firewall */
+ public IntentFirewall getIntentFirewall() {
+ return null;
+ }
}
@Override
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 3487ae3..4f46ecd 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -422,7 +422,9 @@
mStats.setExternalStatsSyncLocked(mWorker);
mStats.setRadioScanningTimeoutLocked(mContext.getResources().getInteger(
com.android.internal.R.integer.config_radioScanningTimeout) * 1000L);
- mStats.startTrackingSystemServerCpuTime();
+ if (!Flags.disableSystemServicePowerAttr()) {
+ mStats.startTrackingSystemServerCpuTime();
+ }
mAggregatedPowerStatsConfig = createAggregatedPowerStatsConfig();
mPowerStatsStore = new PowerStatsStore(systemDir, mHandler, mAggregatedPowerStatsConfig);
diff --git a/services/core/java/com/android/server/am/CachedAppOptimizer.java b/services/core/java/com/android/server/am/CachedAppOptimizer.java
index 626b70b..d92a24b 100644
--- a/services/core/java/com/android/server/am/CachedAppOptimizer.java
+++ b/services/core/java/com/android/server/am/CachedAppOptimizer.java
@@ -1419,6 +1419,11 @@
}
@GuardedBy({"mAm", "mProcLock"})
+ void freezeAppAsyncAtEarliestLSP(ProcessRecord app) {
+ freezeAppAsyncLSP(app, updateEarliestFreezableTime(app, 0));
+ }
+
+ @GuardedBy({"mAm", "mProcLock"})
void freezeAppAsyncInternalLSP(ProcessRecord app, @UptimeMillisLong long delayMillis,
boolean force) {
final ProcessCachedOptimizerRecord opt = app.mOptRecord;
@@ -1714,6 +1719,14 @@
compactApp(frozenProc, CompactProfile.FULL, CompactSource.APP, false);
}
}
+ frozenProc.onProcessFrozen();
+ }
+
+ /**
+ * Callback received when an attempt to freeze a process is cancelled (failed).
+ */
+ void onProcessFrozenCancelled(ProcessRecord app) {
+ app.onProcessFrozenCancelled();
}
/**
@@ -2203,6 +2216,8 @@
onProcessFrozen(proc);
removeMessages(DEADLOCK_WATCHDOG_MSG);
sendEmptyMessageDelayed(DEADLOCK_WATCHDOG_MSG, FREEZE_DEADLOCK_TIMEOUT_MS);
+ } else {
+ onProcessFrozenCancelled(proc);
}
} break;
case REPORT_UNFREEZE_MSG: {
@@ -2460,7 +2475,7 @@
pr = mAm.mPidsSelfLocked.get(blocked);
}
if (pr != null
- && pr.mState.getCurAdj() < ProcessList.CACHED_APP_MIN_ADJ) {
+ && pr.mState.getCurAdj() < ProcessList.FREEZER_CUTOFF_ADJ) {
Slog.d(TAG_AM, app.processName + " (" + pid + ") blocks "
+ pr.processName + " (" + blocked + ")");
// Found at least one blocked non-cached process
diff --git a/services/core/java/com/android/server/am/ContentProviderHelper.java b/services/core/java/com/android/server/am/ContentProviderHelper.java
index 30f21a6..cb7898d 100644
--- a/services/core/java/com/android/server/am/ContentProviderHelper.java
+++ b/services/core/java/com/android/server/am/ContentProviderHelper.java
@@ -35,6 +35,7 @@
import static com.android.internal.util.FrameworkStatsLog.PROVIDER_ACQUISITION_EVENT_REPORTED__PROC_START_TYPE__PROCESS_START_TYPE_WARM;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_MU;
import static com.android.server.am.ActivityManagerService.TAG_MU;
+import static com.android.server.am.Flags.serviceBindingOomAdjPolicy;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
@@ -319,8 +320,10 @@
checkTime(startTime, "getContentProviderImpl: before updateOomAdj");
final int verifiedAdj = cpr.proc.mState.getVerifiedAdj();
- boolean success = mService.updateOomAdjLocked(cpr.proc,
- OOM_ADJ_REASON_GET_PROVIDER);
+ boolean success = !serviceBindingOomAdjPolicy()
+ || mService.mOomAdjuster.evaluateProviderConnectionAdd(r, cpr.proc)
+ ? mService.updateOomAdjLocked(cpr.proc, OOM_ADJ_REASON_GET_PROVIDER)
+ : true;
// XXX things have changed so updateOomAdjLocked doesn't actually tell us
// if the process has been successfully adjusted. So to reduce races with
// it, we will check whether the process still exists. Note that this doesn't
@@ -1529,7 +1532,9 @@
}
mService.stopAssociationLocked(conn.client.uid, conn.client.processName, cpr.uid,
cpr.appInfo.longVersionCode, cpr.name, cpr.info.processName);
- if (updateOomAdj) {
+ if (updateOomAdj && (!serviceBindingOomAdjPolicy()
+ || mService.mOomAdjuster.evaluateProviderConnectionRemoval(conn.client,
+ cpr.proc))) {
mService.updateOomAdjLocked(conn.provider.proc, OOM_ADJ_REASON_REMOVE_PROVIDER);
}
}
diff --git a/services/core/java/com/android/server/am/IntentBindRecord.java b/services/core/java/com/android/server/am/IntentBindRecord.java
index abc7ab1..db47e3f 100644
--- a/services/core/java/com/android/server/am/IntentBindRecord.java
+++ b/services/core/java/com/android/server/am/IntentBindRecord.java
@@ -46,9 +46,17 @@
boolean hasBound;
/** Set when the service's onUnbind() has asked to be told about new clients. */
boolean doRebind;
-
+
String stringName; // caching of toString
-
+
+ /**
+ * Mark if we've skipped oom adj update before calling into the {@link Service#onBind()}
+ * or {@link Service#onUnbind()}.
+ *
+ * <p>If it's true, we'll skip the oom adj update too during the serviceDoneExecuting.
+ */
+ boolean mSkippedOomAdj;
+
void dump(PrintWriter pw, String prefix) {
pw.print(prefix); pw.print("service="); pw.println(service);
dumpInService(pw, prefix);
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index ef7a0e0..862542e 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -103,6 +103,7 @@
import static com.android.server.am.ProcessList.CACHED_APP_MAX_ADJ;
import static com.android.server.am.ProcessList.CACHED_APP_MIN_ADJ;
import static com.android.server.am.ProcessList.FOREGROUND_APP_ADJ;
+import static com.android.server.am.ProcessList.FREEZER_CUTOFF_ADJ;
import static com.android.server.am.ProcessList.HEAVY_WEIGHT_APP_ADJ;
import static com.android.server.am.ProcessList.HOME_APP_ADJ;
import static com.android.server.am.ProcessList.INVALID_ADJ;
@@ -2309,7 +2310,7 @@
}
computeServiceHostOomAdjLSP(cr, app, cr.binding.client, now, topApp, doingAll,
- cycleReEval, computeClients, oomAdjReason, cachedAdj, true);
+ cycleReEval, computeClients, oomAdjReason, cachedAdj, true, false);
adj = state.getCurRawAdj();
procState = state.getCurRawProcState();
@@ -2341,7 +2342,7 @@
ContentProviderConnection conn = cpr.connections.get(i);
ProcessRecord client = conn.client;
computeProviderHostOomAdjLSP(conn, app, client, now, topApp, doingAll,
- cycleReEval, computeClients, oomAdjReason, cachedAdj, true);
+ cycleReEval, computeClients, oomAdjReason, cachedAdj, true, false);
adj = state.getCurRawAdj();
procState = state.getCurRawProcState();
@@ -2558,17 +2559,18 @@
}
@GuardedBy({"mService", "mProcLock"})
- protected void computeServiceHostOomAdjLSP(ConnectionRecord cr, ProcessRecord app,
+ protected boolean computeServiceHostOomAdjLSP(ConnectionRecord cr, ProcessRecord app,
ProcessRecord client, long now, ProcessRecord topApp, boolean doingAll,
boolean cycleReEval, boolean computeClients, int oomAdjReason, int cachedAdj,
- boolean couldRecurse) {
+ boolean couldRecurse, boolean dryRun) {
if (app.isPendingFinishAttach()) {
// We've set the attaching process state in the computeInitialOomAdjLSP. Skip it here.
- return;
+ return false;
}
final ProcessStateRecord state = app.mState;
ProcessStateRecord cstate = client.mState;
+ boolean updated = false;
if (couldRecurse) {
if (app.isSdkSandbox && cr.binding.attributedClient != null) {
@@ -2599,19 +2601,25 @@
final int prevRawAdj = adj;
final int prevProcState = procState;
final int prevSchedGroup = schedGroup;
+ final int prevCapability = capability;
final int appUid = app.info.uid;
final int logUid = mService.mCurOomAdjUid;
- state.setCurBoundByNonBgRestrictedApp(state.isCurBoundByNonBgRestrictedApp()
- || cstate.isCurBoundByNonBgRestrictedApp()
- || clientProcState <= PROCESS_STATE_BOUND_TOP
- || (clientProcState == PROCESS_STATE_FOREGROUND_SERVICE
- && !cstate.isBackgroundRestricted()));
+ if (!dryRun) {
+ state.setCurBoundByNonBgRestrictedApp(state.isCurBoundByNonBgRestrictedApp()
+ || cstate.isCurBoundByNonBgRestrictedApp()
+ || clientProcState <= PROCESS_STATE_BOUND_TOP
+ || (clientProcState == PROCESS_STATE_FOREGROUND_SERVICE
+ && !cstate.isBackgroundRestricted()));
+ }
if (client.mOptRecord.shouldNotFreeze()) {
// Propagate the shouldNotFreeze flag down the bindings.
- app.mOptRecord.setShouldNotFreeze(true);
+ if (app.mOptRecord.setShouldNotFreeze(true, dryRun)) {
+ // Bail out early, as we only care about the return value for a dryrun.
+ return true;
+ }
}
boolean trackedProcState = false;
@@ -2653,7 +2661,7 @@
}
if (couldRecurse && shouldSkipDueToCycle(app, cstate, procState, adj, cycleReEval)) {
- return;
+ return false;
}
if (clientProcState >= PROCESS_STATE_CACHED_ACTIVITY) {
@@ -2666,7 +2674,10 @@
if (cr.hasFlag(Context.BIND_ALLOW_OOM_MANAGEMENT)) {
// Similar to BIND_WAIVE_PRIORITY, keep it unfrozen.
if (clientAdj < CACHED_APP_MIN_ADJ) {
- app.mOptRecord.setShouldNotFreeze(true);
+ if (app.mOptRecord.setShouldNotFreeze(true, dryRun)) {
+ // Bail out early, as we only care about the return value for a dryrun.
+ return true;
+ }
}
// Not doing bind OOM management, so treat
// this guy more like a started service.
@@ -2678,7 +2689,10 @@
if (adj > clientAdj) {
adjType = "cch-bound-ui-services";
}
- state.setCached(false);
+ if (state.setCached(false, dryRun)) {
+ // Bail out early, as we only care about the return value for a dryrun.
+ return true;
+ }
clientAdj = adj;
clientProcState = procState;
} else {
@@ -2721,7 +2735,9 @@
newAdj = PERSISTENT_SERVICE_ADJ;
schedGroup = SCHED_GROUP_DEFAULT;
procState = ActivityManager.PROCESS_STATE_PERSISTENT;
- cr.trackProcState(procState, mAdjSeq);
+ if (!dryRun) {
+ cr.trackProcState(procState, mAdjSeq);
+ }
trackedProcState = true;
}
} else if (cr.hasFlag(Context.BIND_NOT_PERCEPTIBLE)
@@ -2762,11 +2778,16 @@
}
}
if (!cstate.isCached()) {
- state.setCached(false);
+ if (state.setCached(false, dryRun)) {
+ // Bail out early, as we only care about the return value for a dryrun.
+ return true;
+ }
}
if (adj > newAdj) {
adj = newAdj;
- state.setCurRawAdj(adj);
+ if (state.setCurRawAdj(adj, dryRun)) {
+ // Bail out early, as we only care about the return value for a dryrun.
+ }
adjType = "service";
}
}
@@ -2833,25 +2854,35 @@
if (cr.hasFlag(Context.BIND_SCHEDULE_LIKE_TOP_APP) && clientIsSystem) {
schedGroup = SCHED_GROUP_TOP_APP;
- state.setScheduleLikeTopApp(true);
+ if (dryRun) {
+ if (prevSchedGroup < schedGroup) {
+ // Bail out early, as we only care about the return value for a dryrun.
+ return true;
+ }
+ } else {
+ state.setScheduleLikeTopApp(true);
+ }
}
- if (!trackedProcState) {
+ if (!trackedProcState && !dryRun) {
cr.trackProcState(clientProcState, mAdjSeq);
}
if (procState > clientProcState) {
procState = clientProcState;
- state.setCurRawProcState(procState);
+ if (state.setCurRawProcState(procState, dryRun)) {
+ // Bail out early, as we only care about the return value for a dryrun.
+ return true;
+ }
if (adjType == null) {
adjType = "service";
}
}
if (procState < PROCESS_STATE_IMPORTANT_BACKGROUND
- && cr.hasFlag(Context.BIND_SHOWING_UI)) {
+ && cr.hasFlag(Context.BIND_SHOWING_UI) && !dryRun) {
app.setPendingUiClean(true);
}
- if (adjType != null) {
+ if (adjType != null && !dryRun) {
state.setAdjType(adjType);
state.setAdjTypeCode(ActivityManager.RunningAppProcessInfo
.REASON_SERVICE_IN_USE);
@@ -2876,11 +2907,16 @@
// bound by an unfrozen app via a WPRI binding has to remain
// unfrozen.
if (clientAdj < CACHED_APP_MIN_ADJ) {
- app.mOptRecord.setShouldNotFreeze(true);
+ if (app.mOptRecord.setShouldNotFreeze(true, dryRun)) {
+ // Bail out early, as we only care about the return value for a dryrun.
+ return true;
+ }
}
}
if (cr.hasFlag(Context.BIND_TREAT_LIKE_ACTIVITY)) {
- app.mServices.setTreatLikeActivity(true);
+ if (!dryRun) {
+ app.mServices.setTreatLikeActivity(true);
+ }
if (clientProcState <= PROCESS_STATE_CACHED_ACTIVITY
&& procState > PROCESS_STATE_CACHED_ACTIVITY) {
// This is a cached process, but somebody wants us to treat it like it has
@@ -2894,7 +2930,9 @@
if (a != null && adj > FOREGROUND_APP_ADJ
&& a.isActivityVisible()) {
adj = FOREGROUND_APP_ADJ;
- state.setCurRawAdj(adj);
+ if (state.setCurRawAdj(adj, dryRun)) {
+ return true;
+ }
if (cr.notHasFlag(Context.BIND_NOT_FOREGROUND)) {
if (cr.hasFlag(Context.BIND_IMPORTANT)) {
schedGroup = SCHED_GROUP_TOP_APP_BOUND;
@@ -2902,16 +2940,18 @@
schedGroup = SCHED_GROUP_DEFAULT;
}
}
- state.setCached(false);
- state.setAdjType("service");
- state.setAdjTypeCode(ActivityManager.RunningAppProcessInfo
- .REASON_SERVICE_IN_USE);
- state.setAdjSource(a);
- state.setAdjSourceProcState(procState);
- state.setAdjTarget(cr.binding.service.instanceName);
- if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
- reportOomAdjMessageLocked(TAG_OOM_ADJ,
- "Raise to service w/activity: " + app);
+ if (!dryRun) {
+ state.setCached(false);
+ state.setAdjType("service");
+ state.setAdjTypeCode(ActivityManager.RunningAppProcessInfo
+ .REASON_SERVICE_IN_USE);
+ state.setAdjSource(a);
+ state.setAdjSourceProcState(procState);
+ state.setAdjTarget(cr.binding.service.instanceName);
+ if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
+ reportOomAdjMessageLocked(TAG_OOM_ADJ,
+ "Raise to service w/activity: " + app);
+ }
}
}
}
@@ -2922,7 +2962,15 @@
if (procState > PROCESS_STATE_BOUND_FOREGROUND_SERVICE) {
capability &= ~PROCESS_CAPABILITY_BFSL;
}
+ if (!updated) {
+ updated = adj < prevRawAdj || procState < prevProcState || schedGroup > prevSchedGroup
+ || (capability != prevCapability
+ && (capability & prevCapability) == prevCapability);
+ }
+ if (dryRun) {
+ return updated;
+ }
if (adj < prevRawAdj) {
schedGroup = setIntermediateAdjLSP(app, adj, prevRawAdj, schedGroup);
}
@@ -2935,15 +2983,16 @@
state.setCurCapability(capability);
state.setEmpty(false);
+ return updated;
}
- protected void computeProviderHostOomAdjLSP(ContentProviderConnection conn, ProcessRecord app,
- ProcessRecord client, long now, ProcessRecord topApp, boolean doingAll,
- boolean cycleReEval, boolean computeClients, int oomAdjReason, int cachedAdj,
- boolean couldRecurse) {
+ protected boolean computeProviderHostOomAdjLSP(ContentProviderConnection conn,
+ ProcessRecord app, ProcessRecord client, long now, ProcessRecord topApp,
+ boolean doingAll, boolean cycleReEval, boolean computeClients, int oomAdjReason,
+ int cachedAdj, boolean couldRecurse, boolean dryRun) {
if (app.isPendingFinishAttach()) {
// We've set the attaching process state in the computeInitialOomAdjLSP. Skip it here.
- return;
+ return false;
}
final ProcessStateRecord state = app.mState;
@@ -2951,7 +3000,7 @@
if (client == app) {
// Being our own client is not interesting.
- return;
+ return false;
}
if (couldRecurse) {
if (computeClients) {
@@ -2964,7 +3013,7 @@
if (shouldSkipDueToCycle(app, cstate, state.getCurRawProcState(), state.getCurRawAdj(),
cycleReEval)) {
- return;
+ return false;
}
}
@@ -2979,6 +3028,7 @@
final int prevRawAdj = adj;
final int prevProcState = procState;
final int prevSchedGroup = schedGroup;
+ final int prevCapability = capability;
final int appUid = app.info.uid;
final int logUid = mService.mCurOomAdjUid;
@@ -2995,14 +3045,19 @@
}
if (client.mOptRecord.shouldNotFreeze()) {
// Propagate the shouldNotFreeze flag down the bindings.
- app.mOptRecord.setShouldNotFreeze(true);
+ if (app.mOptRecord.setShouldNotFreeze(true, dryRun)) {
+ // Bail out early, as we only care about the return value for a dryrun.
+ return true;
+ }
}
- state.setCurBoundByNonBgRestrictedApp(state.isCurBoundByNonBgRestrictedApp()
- || cstate.isCurBoundByNonBgRestrictedApp()
- || clientProcState <= PROCESS_STATE_BOUND_TOP
- || (clientProcState == PROCESS_STATE_FOREGROUND_SERVICE
- && !cstate.isBackgroundRestricted()));
+ if (!dryRun) {
+ state.setCurBoundByNonBgRestrictedApp(state.isCurBoundByNonBgRestrictedApp()
+ || cstate.isCurBoundByNonBgRestrictedApp()
+ || clientProcState <= PROCESS_STATE_BOUND_TOP
+ || (clientProcState == PROCESS_STATE_FOREGROUND_SERVICE
+ && !cstate.isBackgroundRestricted()));
+ }
String adjType = null;
if (adj > clientAdj) {
@@ -3011,10 +3066,16 @@
adjType = "cch-ui-provider";
} else {
adj = Math.max(clientAdj, FOREGROUND_APP_ADJ);
- state.setCurRawAdj(adj);
+ if (state.setCurRawAdj(adj, dryRun)) {
+ // Bail out early, as we only care about the return value for a dryrun.
+ return true;
+ }
adjType = "provider";
}
- state.setCached(state.isCached() & cstate.isCached());
+ if (state.setCached(state.isCached() & cstate.isCached(), dryRun)) {
+ // Bail out early, as we only care about the return value for a dryrun.
+ return true;
+ }
}
if (clientProcState <= PROCESS_STATE_FOREGROUND_SERVICE) {
@@ -3028,15 +3089,20 @@
}
}
- conn.trackProcState(clientProcState, mAdjSeq);
+ if (!dryRun) {
+ conn.trackProcState(clientProcState, mAdjSeq);
+ }
if (procState > clientProcState) {
procState = clientProcState;
- state.setCurRawProcState(procState);
+ if (state.setCurRawProcState(procState, dryRun)) {
+ // Bail out early, as we only care about the return value for a dryrun.
+ return true;
+ }
}
if (cstate.getCurrentSchedulingGroup() > schedGroup) {
schedGroup = SCHED_GROUP_DEFAULT;
}
- if (adjType != null) {
+ if (adjType != null && !dryRun) {
state.setAdjType(adjType);
state.setAdjTypeCode(ActivityManager.RunningAppProcessInfo
.REASON_PROVIDER_IN_USE);
@@ -3056,6 +3122,12 @@
capability &= ~PROCESS_CAPABILITY_BFSL;
}
+ if (dryRun && (adj < prevRawAdj || procState < prevProcState || schedGroup > prevSchedGroup
+ || (capability != prevCapability
+ && (capability & prevCapability) == prevCapability))) {
+ return true;
+ }
+
if (adj < prevRawAdj) {
schedGroup = setIntermediateAdjLSP(app, adj, prevRawAdj, schedGroup);
}
@@ -3068,6 +3140,7 @@
state.setCurCapability(capability);
state.setEmpty(false);
+ return false;
}
protected int getDefaultCapability(ProcessRecord app, int procState) {
@@ -3342,7 +3415,7 @@
changes |= ActivityManagerService.ProcessChangeItem.CHANGE_ACTIVITIES;
}
- updateAppFreezeStateLSP(app, oomAdjReson);
+ updateAppFreezeStateLSP(app, oomAdjReson, false);
if (state.getReportedProcState() != state.getCurProcState()) {
state.setReportedProcState(state.getCurProcState());
@@ -3727,7 +3800,8 @@
}
@GuardedBy({"mService", "mProcLock"})
- private void updateAppFreezeStateLSP(ProcessRecord app, @OomAdjReason int oomAdjReason) {
+ void updateAppFreezeStateLSP(ProcessRecord app, @OomAdjReason int oomAdjReason,
+ boolean immediate) {
if (!mCachedAppOptimizer.useFreezer()) {
return;
}
@@ -3746,10 +3820,14 @@
final ProcessStateRecord state = app.mState;
// Use current adjustment when freezing, set adjustment when unfreezing.
- if (state.getCurAdj() >= CACHED_APP_MIN_ADJ && !opt.isFrozen()
+ if (state.getCurAdj() >= FREEZER_CUTOFF_ADJ && !opt.isFrozen()
&& !opt.shouldNotFreeze()) {
- mCachedAppOptimizer.freezeAppAsyncLSP(app);
- } else if (state.getSetAdj() < CACHED_APP_MIN_ADJ) {
+ if (!immediate) {
+ mCachedAppOptimizer.freezeAppAsyncLSP(app);
+ } else {
+ mCachedAppOptimizer.freezeAppAsyncAtEarliestLSP(app);
+ }
+ } else if (state.getSetAdj() < FREEZER_CUTOFF_ADJ) {
mCachedAppOptimizer.unfreezeAppLSP(app,
CachedAppOptimizer.getUnfreezeReasonCodeFromOomAdjReason(oomAdjReason));
}
@@ -3826,4 +3904,89 @@
// The caller will set the initial value in this implementation.
return app.mState.isCurBoundByNonBgRestrictedApp();
}
+
+ /**
+ * Evaluate the service connection, return {@code true} if the client will change the state
+ * of the service host process by the given connection.
+ */
+ @GuardedBy("mService")
+ boolean evaluateServiceConnectionAdd(ProcessRecord client, ProcessRecord app,
+ ConnectionRecord cr) {
+ if (evaluateConnectionPrelude(client, app)) {
+ return true;
+ }
+ if (app.getSetAdj() <= client.getSetAdj()
+ && app.getSetProcState() <= client.getSetProcState()
+ && ((app.getSetCapability() & client.getSetCapability())
+ == client.getSetCapability()
+ || cr.notHasFlag(Context.BIND_INCLUDE_CAPABILITIES
+ | Context.BIND_BYPASS_USER_NETWORK_RESTRICTIONS))) {
+ // The service host process has better states than the client, so no change.
+ return false;
+ }
+ // Take a dry run of the computeServiceHostOomAdjLSP, this would't be expensive
+ // since it's only evaluating one service connection.
+ return computeServiceHostOomAdjLSP(cr, app, client, SystemClock.uptimeMillis(),
+ mService.getTopApp(), false, false, false, OOM_ADJ_REASON_NONE,
+ CACHED_APP_MIN_ADJ, false, true /* dryRun */);
+ }
+
+ @GuardedBy("mService")
+ boolean evaluateServiceConnectionRemoval(ProcessRecord client, ProcessRecord app,
+ ConnectionRecord cr) {
+ if (evaluateConnectionPrelude(client, app)) {
+ return true;
+ }
+
+ if (app.getSetAdj() < client.getSetAdj()
+ && app.getSetProcState() < client.getSetProcState()) {
+ // The service host process has better states than the client.
+ if (((app.getSetCapability() & client.getSetCapability()) == PROCESS_CAPABILITY_NONE)
+ || cr.notHasFlag(Context.BIND_INCLUDE_CAPABILITIES
+ | Context.BIND_BYPASS_USER_NETWORK_RESTRICTIONS)) {
+ // The service host app doesn't get any capabilities from the client.
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @GuardedBy("mService")
+ boolean evaluateProviderConnectionAdd(ProcessRecord client, ProcessRecord app) {
+ if (evaluateConnectionPrelude(client, app)) {
+ return true;
+ }
+ if (app.getSetAdj() <= client.getSetAdj()
+ && app.getSetProcState() <= client.getSetProcState()) {
+ // The provider host process has better states than the client, so no change.
+ return false;
+ }
+ return computeProviderHostOomAdjLSP(null, app, client, SystemClock.uptimeMillis(),
+ mService.getTopApp(), false, false, false, OOM_ADJ_REASON_NONE, CACHED_APP_MIN_ADJ,
+ false, true /* dryRun */);
+ }
+
+ @GuardedBy("mService")
+ boolean evaluateProviderConnectionRemoval(ProcessRecord client, ProcessRecord app) {
+ if (evaluateConnectionPrelude(client, app)) {
+ return true;
+ }
+ if (app.getSetAdj() < client.getSetAdj()
+ && app.getSetProcState() < client.getSetProcState()) {
+ // The provider host process has better states than the client, so no change.
+ return false;
+ }
+ return true;
+ }
+
+ private boolean evaluateConnectionPrelude(ProcessRecord client, ProcessRecord app) {
+ if (client == null || app == null) {
+ return true;
+ }
+ if (app.isSdkSandbox || app.isolated || app.isKilledByAm() || app.isKilled()) {
+ // Let's always re-evaluate them for now.
+ return true;
+ }
+ return false;
+ }
}
diff --git a/services/core/java/com/android/server/am/OomAdjusterModernImpl.java b/services/core/java/com/android/server/am/OomAdjusterModernImpl.java
index 5a3fbe9..f85b03e 100644
--- a/services/core/java/com/android/server/am/OomAdjusterModernImpl.java
+++ b/services/core/java/com/android/server/am/OomAdjusterModernImpl.java
@@ -1002,7 +1002,7 @@
computeServiceHostOomAdjLSP(cr, service, app, now, topApp, fullUpdate, false, false,
- oomAdjReason, cachedAdj, false);
+ oomAdjReason, cachedAdj, false, false);
}
for (int i = psr.numberOfSdkSandboxConnections() - 1; i >= 0; i--) {
@@ -1018,7 +1018,7 @@
}
computeServiceHostOomAdjLSP(cr, service, app, now, topApp, fullUpdate, false, false,
- oomAdjReason, cachedAdj, false);
+ oomAdjReason, cachedAdj, false, false);
}
final ProcessProviderRecord ppr = app.mProviders;
@@ -1035,7 +1035,7 @@
}
computeProviderHostOomAdjLSP(cpc, provider, app, now, topApp, fullUpdate, false, false,
- oomAdjReason, cachedAdj, false);
+ oomAdjReason, cachedAdj, false, false);
}
}
}
diff --git a/services/core/java/com/android/server/am/PendingIntentController.java b/services/core/java/com/android/server/am/PendingIntentController.java
index a20623c..5df9107 100644
--- a/services/core/java/com/android/server/am/PendingIntentController.java
+++ b/services/core/java/com/android/server/am/PendingIntentController.java
@@ -30,6 +30,7 @@
import android.app.AppGlobals;
import android.app.PendingIntent;
import android.app.PendingIntentStats;
+import android.app.compat.CompatChanges;
import android.content.IIntentSender;
import android.content.Intent;
import android.os.Binder;
@@ -136,6 +137,11 @@
+ "intent creator ("
+ packageName
+ ") because this option is meant for the pending intent sender");
+ if (CompatChanges.isChangeEnabled(PendingIntent.PENDING_INTENT_OPTIONS_CHECK,
+ callingUid)) {
+ throw new IllegalArgumentException("pendingIntentBackgroundActivityStartMode "
+ + "must not be set when creating a PendingIntent");
+ }
opts.setPendingIntentBackgroundActivityStartMode(
ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED);
}
diff --git a/services/core/java/com/android/server/am/PendingIntentRecord.java b/services/core/java/com/android/server/am/PendingIntentRecord.java
index 10d5fd3..95e130e 100644
--- a/services/core/java/com/android/server/am/PendingIntentRecord.java
+++ b/services/core/java/com/android/server/am/PendingIntentRecord.java
@@ -406,6 +406,9 @@
String resolvedType, IBinder allowlistToken, IIntentReceiver finishedReceiver,
String requiredPermission, IBinder resultTo, String resultWho, int requestCode,
int flagsMask, int flagsValues, Bundle options) {
+ final int callingUid = Binder.getCallingUid();
+ final int callingPid = Binder.getCallingPid();
+
if (intent != null) intent.setDefusable(true);
if (options != null) options.setDefusable(true);
@@ -458,6 +461,12 @@
+ key.packageName
+ ") because this option is meant for the pending intent "
+ "creator");
+ if (CompatChanges.isChangeEnabled(PendingIntent.PENDING_INTENT_OPTIONS_CHECK,
+ callingUid)) {
+ throw new IllegalArgumentException(
+ "pendingIntentCreatorBackgroundActivityStartMode "
+ + "must not be set when sending a PendingIntent");
+ }
opts.setPendingIntentCreatorBackgroundActivityStartMode(
ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_SYSTEM_DEFINED);
}
@@ -494,9 +503,6 @@
}
// We don't hold the controller lock beyond this point as we will be calling into AM and WM.
- final int callingUid = Binder.getCallingUid();
- final int callingPid = Binder.getCallingPid();
-
// Only system senders can declare a broadcast to be alarm-originated. We check
// this here rather than in the general case handling below to fail before the other
// invocation side effects such as allowlisting.
diff --git a/services/core/java/com/android/server/am/ProcessCachedOptimizerRecord.java b/services/core/java/com/android/server/am/ProcessCachedOptimizerRecord.java
index f5c5ea8..a8fe734 100644
--- a/services/core/java/com/android/server/am/ProcessCachedOptimizerRecord.java
+++ b/services/core/java/com/android/server/am/ProcessCachedOptimizerRecord.java
@@ -274,7 +274,20 @@
@GuardedBy("mProcLock")
void setShouldNotFreeze(boolean shouldNotFreeze) {
+ setShouldNotFreeze(shouldNotFreeze, false);
+ }
+
+ /**
+ * @return {@code true} if it's a dry run and it's going to unfreeze the process
+ * if it was a real run.
+ */
+ @GuardedBy("mProcLock")
+ boolean setShouldNotFreeze(boolean shouldNotFreeze, boolean dryRun) {
+ if (dryRun) {
+ return mFrozen && !shouldNotFreeze;
+ }
mShouldNotFreeze = shouldNotFreeze;
+ return false;
}
@GuardedBy("mProcLock")
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index f5c34a5..10cd6e5 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -371,6 +371,12 @@
private static final long LMKD_RECONNECT_DELAY_MS = 1000;
/**
+ * The cuttoff adj for the freezer, app processes with adj greater than this value will be
+ * eligible for the freezer.
+ */
+ static final int FREEZER_CUTOFF_ADJ = CACHED_APP_MIN_ADJ;
+
+ /**
* Apps have no access to the private data directories of any other app, even if the other
* app has made them world-readable.
*/
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index e5c4a66..de6f034 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -720,6 +720,11 @@
return mState.getSetProcState();
}
+ @GuardedBy(anyOf = {"mService", "mProcLock"})
+ int getSetCapability() {
+ return mState.getSetCapability();
+ }
+
@GuardedBy({"mService", "mProcLock"})
public void makeActive(IApplicationThread thread, ProcessStatsService tracker) {
mProfile.onProcessActive(thread, tracker);
@@ -1401,8 +1406,12 @@
void onProcessUnfrozen() {
mProfile.onProcessUnfrozen();
+ mServices.onProcessUnfrozen();
}
+ void onProcessFrozenCancelled() {
+ mServices.onProcessFrozenCancelled();
+ }
/*
* Delete all packages from list except the package indicated in info
@@ -1644,6 +1653,13 @@
return mWasForceStopped;
}
+ boolean isFreezable() {
+ return mService.mOomAdjuster.mCachedAppOptimizer.useFreezer()
+ && !mOptRecord.isFreezeExempt()
+ && !mOptRecord.shouldNotFreeze()
+ && mState.getCurAdj() >= ProcessList.FREEZER_CUTOFF_ADJ;
+ }
+
/**
* Traverses all client processes and feed them to consumer.
*/
diff --git a/services/core/java/com/android/server/am/ProcessServiceRecord.java b/services/core/java/com/android/server/am/ProcessServiceRecord.java
index f5f2b10..57d233e 100644
--- a/services/core/java/com/android/server/am/ProcessServiceRecord.java
+++ b/services/core/java/com/android/server/am/ProcessServiceRecord.java
@@ -19,6 +19,8 @@
import static android.app.ProcessMemoryState.HOSTING_COMPONENT_TYPE_BOUND_SERVICE;
import static android.app.ProcessMemoryState.HOSTING_COMPONENT_TYPE_FOREGROUND_SERVICE;
+import static com.android.server.am.Flags.serviceBindingOomAdjPolicy;
+
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.content.Context;
@@ -144,6 +146,11 @@
*/
private ArraySet<Integer> mBoundClientUids = new ArraySet<>();
+ /**
+ * The process should schedule a service timeout timer but haven't done so.
+ */
+ private boolean mScheduleServiceTimeoutPending;
+
final ProcessRecord mApp;
private final ActivityManagerService mService;
@@ -657,6 +664,41 @@
setHasClientActivities(false);
}
+ @GuardedBy("mService")
+ void noteScheduleServiceTimeoutPending(boolean pending) {
+ mScheduleServiceTimeoutPending = pending;
+ }
+
+ @GuardedBy("mService")
+ boolean isScheduleServiceTimeoutPending() {
+ return mScheduleServiceTimeoutPending;
+ }
+
+ @GuardedBy("mService")
+ void onProcessUnfrozen() {
+ scheduleServiceTimeoutIfNeededLocked();
+ }
+
+ @GuardedBy("mService")
+ void onProcessFrozenCancelled() {
+ scheduleServiceTimeoutIfNeededLocked();
+ }
+
+ @GuardedBy("mService")
+ private void scheduleServiceTimeoutIfNeededLocked() {
+ if (!serviceBindingOomAdjPolicy()) {
+ return;
+ }
+ if (mScheduleServiceTimeoutPending && mExecutingServices.size() > 0) {
+ mService.mServices.scheduleServiceTimeoutLocked(mApp);
+ // We'll need to reset the executingStart since the app was frozen.
+ final long now = SystemClock.uptimeMillis();
+ for (int i = 0, size = mExecutingServices.size(); i < size; i++) {
+ mExecutingServices.valueAt(i).executingStart = now;
+ }
+ }
+ }
+
void dump(PrintWriter pw, String prefix, long nowUptime) {
if (mHasForegroundServices || mApp.mState.getForcingToImportant() != null) {
pw.print(prefix); pw.print("mHasForegroundServices="); pw.print(mHasForegroundServices);
@@ -701,5 +743,10 @@
pw.print(prefix); pw.print(" - "); pw.println(mConnections.valueAt(i));
}
}
+ if (serviceBindingOomAdjPolicy()) {
+ pw.print(prefix);
+ pw.print("scheduleServiceTimeoutPending=");
+ pw.println(mScheduleServiceTimeoutPending);
+ }
}
}
diff --git a/services/core/java/com/android/server/am/ProcessStateRecord.java b/services/core/java/com/android/server/am/ProcessStateRecord.java
index 3391ec7..8362eaf 100644
--- a/services/core/java/com/android/server/am/ProcessStateRecord.java
+++ b/services/core/java/com/android/server/am/ProcessStateRecord.java
@@ -479,9 +479,22 @@
@GuardedBy({"mService", "mProcLock"})
void setCurRawAdj(int curRawAdj) {
+ setCurRawAdj(curRawAdj, false);
+ }
+
+ /**
+ * @return {@code true} if it's a dry run and it's going to bump the adj score of the process
+ * if it was a real run.
+ */
+ @GuardedBy({"mService", "mProcLock"})
+ boolean setCurRawAdj(int curRawAdj, boolean dryRun) {
+ if (dryRun) {
+ return mCurRawAdj > curRawAdj;
+ }
mCurRawAdj = curRawAdj;
mApp.getWindowProcessController().setPerceptible(
curRawAdj <= ProcessList.PERCEPTIBLE_APP_ADJ);
+ return false;
}
@GuardedBy(anyOf = {"mService", "mProcLock"})
@@ -594,7 +607,20 @@
@GuardedBy({"mService", "mProcLock"})
void setCurRawProcState(int curRawProcState) {
+ setCurRawProcState(curRawProcState, false);
+ }
+
+ /**
+ * @return {@code true} if it's a dry run and it's going to bump the procstate of the process
+ * if it was a real run.
+ */
+ @GuardedBy({"mService", "mProcLock"})
+ boolean setCurRawProcState(int curRawProcState, boolean dryRun) {
+ if (dryRun) {
+ return mCurRawProcState > curRawProcState;
+ }
mCurRawProcState = curRawProcState;
+ return false;
}
@GuardedBy(anyOf = {"mService", "mProcLock"})
@@ -900,7 +926,20 @@
@GuardedBy("mService")
void setCached(boolean cached) {
+ setCached(cached, false);
+ }
+
+ /**
+ * @return {@code true} if it's a dry run and it's going to uncache the process
+ * if it was a real run.
+ */
+ @GuardedBy("mService")
+ boolean setCached(boolean cached, boolean dryRun) {
+ if (dryRun) {
+ return mCached && !cached;
+ }
mCached = cached;
+ return false;
}
@GuardedBy("mService")
diff --git a/services/core/java/com/android/server/am/flags.aconfig b/services/core/java/com/android/server/am/flags.aconfig
index 654aebd..31d9cc9 100644
--- a/services/core/java/com/android/server/am/flags.aconfig
+++ b/services/core/java/com/android/server/am/flags.aconfig
@@ -35,3 +35,10 @@
description: "Enable the new FGS restriction logic"
bug: "276963716"
}
+
+flag {
+ name: "service_binding_oom_adj_policy"
+ namespace: "backstage_power"
+ description: "Optimize the service bindings by different policies like skipping oom adjuster"
+ bug: "318717054"
+}
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index df179a9..5b23364c 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -138,6 +138,7 @@
import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.Random;
import java.util.Set;
@@ -3870,8 +3871,12 @@
final SyncStorageEngine.EndPoint info = syncOperation.target;
if (activeSyncContext.mIsLinkedToDeath) {
- activeSyncContext.mSyncAdapter.asBinder().unlinkToDeath(activeSyncContext, 0);
- activeSyncContext.mIsLinkedToDeath = false;
+ try {
+ activeSyncContext.mSyncAdapter.asBinder().unlinkToDeath(activeSyncContext, 0);
+ activeSyncContext.mIsLinkedToDeath = false;
+ } catch (NoSuchElementException e) {
+ Slog.wtf(TAG, "Failed to unlink active sync adapter to death", e);
+ }
}
final long elapsedTime = SystemClock.elapsedRealtime() - activeSyncContext.mStartTime;
String historyMessage;
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 9cf9119..93addcd 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -1656,14 +1656,16 @@
ContentRecordingSession session = null;
try {
if (projection != null) {
- IBinder launchCookie = projection.getLaunchCookie();
- if (launchCookie == null) {
+ IBinder taskWindowContainerToken = projection.getLaunchCookie() == null ? null
+ : projection.getLaunchCookie().binder;
+ if (taskWindowContainerToken == null) {
// Record a particular display.
session = ContentRecordingSession.createDisplaySession(
virtualDisplayConfig.getDisplayIdToMirror());
} else {
// Record a single task indicated by the launch cookie.
- session = ContentRecordingSession.createTaskSession(launchCookie);
+ session = ContentRecordingSession.createTaskSession(
+ taskWindowContainerToken);
}
}
} catch (RemoteException e) {
@@ -2776,17 +2778,17 @@
}
private ScreenCapture.ScreenshotHardwareBuffer userScreenshotInternal(int displayId) {
+ final ScreenCapture.DisplayCaptureArgs captureArgs;
synchronized (mSyncRoot) {
final IBinder token = getDisplayToken(displayId);
if (token == null) {
return null;
}
- final ScreenCapture.DisplayCaptureArgs captureArgs =
- new ScreenCapture.DisplayCaptureArgs.Builder(token)
+ captureArgs = new ScreenCapture.DisplayCaptureArgs.Builder(token)
.build();
- return ScreenCapture.captureDisplay(captureArgs);
}
+ return ScreenCapture.captureDisplay(captureArgs);
}
@VisibleForTesting
diff --git a/services/core/java/com/android/server/display/mode/DisplayModeDirector.java b/services/core/java/com/android/server/display/mode/DisplayModeDirector.java
index 82461fa..8b4e1ff 100644
--- a/services/core/java/com/android/server/display/mode/DisplayModeDirector.java
+++ b/services/core/java/com/android/server/display/mode/DisplayModeDirector.java
@@ -394,6 +394,8 @@
if (mDisplayObserver.isExternalDisplayLocked(displayId)) {
primarySummary.maxRenderFrameRate = Math.max(baseMode.getRefreshRate(),
primarySummary.maxRenderFrameRate);
+ appRequestSummary.maxRenderFrameRate = Math.max(baseMode.getRefreshRate(),
+ appRequestSummary.maxRenderFrameRate);
}
return new DesiredDisplayModeSpecs(baseMode.getModeId(),
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
index ba4d320..731c78e 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
@@ -514,6 +514,18 @@
protected int handleRoutingInformation(HdmiCecMessage message) {
assertRunOnServiceThread();
int physicalAddress = HdmiUtils.twoBytesToInt(message.getParams());
+ HdmiDeviceInfo sourceDevice = mService.getHdmiCecNetwork()
+ .getCecDeviceInfo(message.getSource());
+ // Ignore <Routing Information> messages pointing to the same physical address as the
+ // message sender. In this case, we shouldn't consider the sender to be the active source.
+ // See more b/321771821#comment7.
+ if (sourceDevice != null
+ && sourceDevice.getLogicalAddress() != Constants.ADDR_TV
+ && sourceDevice.getPhysicalAddress() == physicalAddress) {
+ Slog.d(TAG, "<Routing Information> is ignored, it is pointing to the same physical"
+ + " address as the message sender");
+ return Constants.HANDLED;
+ }
handleRoutingChangeAndInformation(physicalAddress, message);
return Constants.HANDLED;
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index 34e75c0..46061a5 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -482,6 +482,22 @@
@Override
@ServiceThreadOnly
@Constants.HandleMessageResult
+ protected int handleStandby(HdmiCecMessage message) {
+ assertRunOnServiceThread();
+
+ // Ignore <Standby> from non-active source device.
+ if (getActiveSource().logicalAddress != message.getSource()) {
+ Slog.d(TAG, "<Standby> was not sent by the current active source, ignoring."
+ + " Current active source has logical address "
+ + getActiveSource().logicalAddress);
+ return Constants.HANDLED;
+ }
+ return super.handleStandby(message);
+ }
+
+ @Override
+ @ServiceThreadOnly
+ @Constants.HandleMessageResult
protected int handleInactiveSource(HdmiCecMessage message) {
assertRunOnServiceThread();
// Seq #10
diff --git a/services/core/java/com/android/server/inputmethod/ClientController.java b/services/core/java/com/android/server/inputmethod/ClientController.java
index ece236a..86f4db9 100644
--- a/services/core/java/com/android/server/inputmethod/ClientController.java
+++ b/services/core/java/com/android/server/inputmethod/ClientController.java
@@ -17,6 +17,7 @@
package com.android.server.inputmethod;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.content.pm.PackageManagerInternal;
import android.os.IBinder;
import android.os.RemoteException;
@@ -29,6 +30,7 @@
import java.util.ArrayList;
import java.util.List;
+import java.util.function.Consumer;
/**
* Store and manage {@link InputMethodManagerService} clients. This class was designed to be a
@@ -62,7 +64,7 @@
// TODO(b/314150112): Make this field private when breaking the cycle with IMMS.
@GuardedBy("ImfLock.class")
- final ArrayMap<IBinder, ClientState> mClients = new ArrayMap<>();
+ private final ArrayMap<IBinder, ClientState> mClients = new ArrayMap<>();
@GuardedBy("ImfLock.class")
private final List<ClientControllerCallback> mCallbacks = new ArrayList<>();
@@ -145,6 +147,19 @@
}
@GuardedBy("ImfLock.class")
+ @Nullable
+ ClientState getClient(IBinder binder) {
+ return mClients.get(binder);
+ }
+
+ @GuardedBy("ImfLock.class")
+ void forAllClients(Consumer<ClientState> consumer) {
+ for (int i = 0; i < mClients.size(); i++) {
+ consumer.accept(mClients.valueAt(i));
+ }
+ }
+
+ @GuardedBy("ImfLock.class")
boolean verifyClientAndPackageMatch(
@NonNull IInputMethodClient client, @NonNull String packageName) {
final ClientState cs = mClients.get(client.asBinder());
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 4767ebd..f031b7b 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -205,6 +205,7 @@
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Consumer;
import java.util.function.IntConsumer;
/**
@@ -270,7 +271,6 @@
@NonNull
private final String[] mNonPreemptibleInputMethods;
- // TODO(b/314150112): Move this to ClientController.
@UserIdInt
private int mLastSwitchUserId;
@@ -1819,10 +1819,8 @@
}
mLastSwitchUserId = newUserId;
-
if (mIsInteractive && clientToBeReset != null) {
- final ClientState cs =
- mClientController.mClients.get(clientToBeReset.asBinder());
+ final ClientState cs = mClientController.getClient(clientToBeReset.asBinder());
if (cs == null) {
// The client is already gone.
return;
@@ -2165,26 +2163,25 @@
/**
* Hide the IME if the removed user is the current user.
*/
+ @GuardedBy("ImfLock.class")
private void onClientRemoved(ClientState client) {
- synchronized (ImfLock.class) {
- clearClientSessionLocked(client);
- clearClientSessionForAccessibilityLocked(client);
- if (mCurClient == client) {
- hideCurrentInputLocked(mCurFocusedWindow, null /* statsToken */, 0 /* flags */,
- null /* resultReceiver */, SoftInputShowHideReason.HIDE_REMOVE_CLIENT);
- if (mBoundToMethod) {
- mBoundToMethod = false;
- IInputMethodInvoker curMethod = getCurMethodLocked();
- if (curMethod != null) {
- // When we unbind input, we are unbinding the client, so we always
- // unbind ime and a11y together.
- curMethod.unbindInput();
- AccessibilityManagerInternal.get().unbindInput();
- }
+ clearClientSessionLocked(client);
+ clearClientSessionForAccessibilityLocked(client);
+ if (mCurClient == client) {
+ hideCurrentInputLocked(mCurFocusedWindow, null /* statsToken */, 0 /* flags */,
+ null /* resultReceiver */, SoftInputShowHideReason.HIDE_REMOVE_CLIENT);
+ if (mBoundToMethod) {
+ mBoundToMethod = false;
+ IInputMethodInvoker curMethod = getCurMethodLocked();
+ if (curMethod != null) {
+ // When we unbind input, we are unbinding the client, so we always
+ // unbind ime and a11y together.
+ curMethod.unbindInput();
+ AccessibilityManagerInternal.get().unbindInput();
}
- mBoundToAccessibility = false;
- mCurClient = null;
}
+ mBoundToAccessibility = false;
+ mCurClient = null;
if (mCurFocusedWindowClient == client) {
mCurFocusedWindowClient = null;
mCurFocusedWindowEditorInfo = null;
@@ -2192,7 +2189,6 @@
}
}
- // TODO(b/314150112): Move this to ClientController.
@GuardedBy("ImfLock.class")
void unbindCurrentClientLocked(@UnbindReason int unbindClientReason) {
if (mCurClient != null) {
@@ -2883,11 +2879,16 @@
@GuardedBy("ImfLock.class")
void clearClientSessionsLocked() {
if (getCurMethodLocked() != null) {
- final int numClients = mClientController.mClients.size();
- for (int i = 0; i < numClients; ++i) {
- clearClientSessionLocked(mClientController.mClients.valueAt(i));
- clearClientSessionForAccessibilityLocked(mClientController.mClients.valueAt(i));
- }
+ // TODO(b/322816970): Replace this with lambda.
+ mClientController.forAllClients(new Consumer<ClientState>() {
+
+ @GuardedBy("ImfLock.class")
+ @Override
+ public void accept(ClientState c) {
+ clearClientSessionLocked(c);
+ clearClientSessionForAccessibilityLocked(c);
+ }
+ });
finishSessionLocked(mEnabledSession);
for (int i = 0; i < mEnabledAccessibilitySessions.size(); i++) {
@@ -3732,9 +3733,9 @@
return InputBindResult.INVALID_USER;
}
- final ClientState cs = mClientController.mClients.get(client.asBinder());
+ final ClientState cs = mClientController.getClient(client.asBinder());
if (cs == null) {
- throw new IllegalArgumentException("unknown client " + client.asBinder());
+ throw new IllegalArgumentException("Unknown client " + client.asBinder());
}
final int imeClientFocus = mWindowManagerInternal.hasInputMethodClientFocus(
@@ -3906,8 +3907,7 @@
// We need to check if this is the current client with
// focus in the window manager, to allow this call to
// be made before input is started in it.
- final ClientState cs =
- mClientController.mClients.get(client.asBinder());
+ final ClientState cs = mClientController.getClient(client.asBinder());
if (cs == null) {
ImeTracker.forLogging().onFailed(statsToken, ImeTracker.PHASE_SERVER_CLIENT_KNOWN);
throw new IllegalArgumentException("unknown client " + client.asBinder());
@@ -4518,16 +4518,17 @@
@Override
public void startImeTrace() {
super.startImeTrace_enforcePermission();
-
ImeTracing.getInstance().startTrace(null /* printwriter */);
- ArrayMap<IBinder, ClientState> clients;
synchronized (ImfLock.class) {
- clients = new ArrayMap<>(mClientController.mClients);
- }
- for (ClientState state : clients.values()) {
- if (state != null) {
- state.mClient.setImeTraceEnabled(true /* enabled */);
- }
+ // TODO(b/322816970): Replace this with lambda.
+ mClientController.forAllClients(new Consumer<ClientState>() {
+
+ @GuardedBy("ImfLock.class")
+ @Override
+ public void accept(ClientState c) {
+ c.mClient.setImeTraceEnabled(true /* enabled */);
+ }
+ });
}
}
@@ -4538,14 +4539,16 @@
super.stopImeTrace_enforcePermission();
ImeTracing.getInstance().stopTrace(null /* printwriter */);
- ArrayMap<IBinder, ClientState> clients;
synchronized (ImfLock.class) {
- clients = new ArrayMap<>(mClientController.mClients);
- }
- for (ClientState state : clients.values()) {
- if (state != null) {
- state.mClient.setImeTraceEnabled(false /* enabled */);
- }
+ // TODO(b/322816970): Replace this with lambda.
+ mClientController.forAllClients(new Consumer<ClientState>() {
+
+ @GuardedBy("ImfLock.class")
+ @Override
+ public void accept(ClientState c) {
+ c.mClient.setImeTraceEnabled(false /* enabled */);
+ }
+ });
}
}
@@ -5779,11 +5782,15 @@
// We only have sessions when we bound to an input method. Remove this session
// from all clients.
if (getCurMethodLocked() != null) {
- final int numClients = mClientController.mClients.size();
- for (int i = 0; i < numClients; ++i) {
- clearClientSessionForAccessibilityLocked(
- mClientController.mClients.valueAt(i), accessibilityConnectionId);
- }
+ // TODO(b/322816970): Replace this with lambda.
+ mClientController.forAllClients(new Consumer<ClientState>() {
+
+ @GuardedBy("ImfLock.class")
+ @Override
+ public void accept(ClientState c) {
+ clearClientSessionForAccessibilityLocked(c, accessibilityConnectionId);
+ }
+ });
AccessibilitySessionState session = mEnabledAccessibilitySessions.get(
accessibilityConnectionId);
if (session != null) {
@@ -5967,19 +5974,26 @@
p.println(" InputMethod #" + i + ":");
info.dump(p, " ");
}
+ // Dump ClientController#mClients
p.println(" ClientStates:");
- // TODO(b/314150112): move client related dump info to ClientController#dump
- final int numClients = mClientController.mClients.size();
- for (int i = 0; i < numClients; ++i) {
- final ClientState ci = mClientController.mClients.valueAt(i);
- p.println(" " + ci + ":");
- p.println(" client=" + ci.mClient);
- p.println(" fallbackInputConnection=" + ci.mFallbackInputConnection);
- p.println(" sessionRequested=" + ci.mSessionRequested);
- p.println(" sessionRequestedForAccessibility="
- + ci.mSessionRequestedForAccessibility);
- p.println(" curSession=" + ci.mCurSession);
- }
+ // TODO(b/322816970): Replace this with lambda.
+ mClientController.forAllClients(new Consumer<ClientState>() {
+
+ @GuardedBy("ImfLock.class")
+ @Override
+ public void accept(ClientState c) {
+ p.println(" " + c + ":");
+ p.println(" client=" + c.mClient);
+ p.println(" fallbackInputConnection="
+ + c.mFallbackInputConnection);
+ p.println(" sessionRequested="
+ + c.mSessionRequested);
+ p.println(
+ " sessionRequestedForAccessibility="
+ + c.mSessionRequestedForAccessibility);
+ p.println(" curSession=" + c.mCurSession);
+ }
+ });
p.println(" mCurMethodId=" + getSelectedMethodIdLocked());
client = mCurClient;
p.println(" mCurClient=" + client + " mCurSeq=" + getSequenceNumberLocked());
@@ -6583,14 +6597,16 @@
}
}
boolean isImeTraceEnabled = ImeTracing.getInstance().isEnabled();
- ArrayMap<IBinder, ClientState> clients;
synchronized (ImfLock.class) {
- clients = new ArrayMap<>(mClientController.mClients);
- }
- for (ClientState state : clients.values()) {
- if (state != null) {
- state.mClient.setImeTraceEnabled(isImeTraceEnabled);
- }
+ // TODO(b/322816970): Replace this with lambda.
+ mClientController.forAllClients(new Consumer<ClientState>() {
+
+ @GuardedBy("ImfLock.class")
+ @Override
+ public void accept(ClientState c) {
+ c.mClient.setImeTraceEnabled(isImeTraceEnabled);
+ }
+ });
}
return ShellCommandResult.SUCCESS;
}
diff --git a/services/core/java/com/android/server/location/provider/StationaryThrottlingLocationProvider.java b/services/core/java/com/android/server/location/provider/StationaryThrottlingLocationProvider.java
index 5e38bca..2522f7b 100644
--- a/services/core/java/com/android/server/location/provider/StationaryThrottlingLocationProvider.java
+++ b/services/core/java/com/android/server/location/provider/StationaryThrottlingLocationProvider.java
@@ -27,6 +27,7 @@
import android.annotation.Nullable;
import android.location.Location;
+import android.location.LocationRequest;
import android.location.LocationResult;
import android.location.provider.ProviderRequest;
import android.os.SystemClock;
@@ -179,6 +180,7 @@
private void onThrottlingChangedLocked(boolean deliverImmediate) {
long throttlingIntervalMs = INTERVAL_DISABLED;
if (mDeviceStationary && mDeviceIdle && !mIncomingRequest.isLocationSettingsIgnored()
+ && mIncomingRequest.getQuality() != LocationRequest.QUALITY_HIGH_ACCURACY
&& mLastLocation != null
&& mLastLocation.getElapsedRealtimeAgeMillis(mDeviceStationaryRealtimeMs)
<= MAX_STATIONARY_LOCATION_AGE_MS) {
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index 1d516e2..7fabdf2 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -34,6 +34,8 @@
import android.app.KeyguardManager;
import android.app.NotificationManager;
import android.app.PendingIntent;
+import android.app.usage.UsageStatsManager;
+import android.app.usage.UsageStatsManagerInternal;
import android.content.ActivityNotFoundException;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
@@ -68,6 +70,7 @@
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Message;
+import android.os.PersistableBundle;
import android.os.PowerExemptionManager;
import android.os.PowerManager;
import android.os.Process;
@@ -100,7 +103,9 @@
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
+import java.util.Set;
/**
* System implementation of MediaSessionManager
@@ -145,6 +150,8 @@
private AudioManager mAudioManager;
private boolean mHasFeatureLeanback;
private ActivityManagerInternal mActivityManagerInternal;
+ private UsageStatsManagerInternal mUsageStatsManagerInternal;
+ private final Set<Integer> mUserEngagingSessions = new HashSet<>();
// The FullUserRecord of the current users. (i.e. The foreground user that isn't a profile)
// It's always not null after the MediaSessionService is started.
@@ -230,6 +237,7 @@
mContext.registerReceiver(mNotificationListenerEnabledChangedReceiver, filter);
mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
+ mUsageStatsManagerInternal = LocalServices.getService(UsageStatsManagerInternal.class);
}
@Override
@@ -582,12 +590,43 @@
if (allowRunningInForeground) {
mActivityManagerInternal.startForegroundServiceDelegate(
foregroundServiceDelegationOptions, /* connection= */ null);
+ reportMediaInteractionEvent(record, /* userEngaged= */ true);
} else {
mActivityManagerInternal.stopForegroundServiceDelegate(
foregroundServiceDelegationOptions);
+ reportMediaInteractionEvent(record, /* userEngaged= */ false);
}
}
+ private void reportMediaInteractionEvent(MediaSessionRecordImpl record, boolean userEngaged) {
+ if (!android.app.usage.Flags.userInteractionTypeApi()) {
+ return;
+ }
+
+ String packageName = record.getPackageName();
+ int sessionUid = record.getUid();
+ String actionToLog = null;
+ if (userEngaged) {
+ if (!mUserEngagingSessions.contains(sessionUid)) {
+ actionToLog = "start";
+ }
+ mUserEngagingSessions.add(sessionUid);
+ } else {
+ if (mUserEngagingSessions.contains(sessionUid)) {
+ actionToLog = "stop";
+ }
+ mUserEngagingSessions.remove(sessionUid);
+ }
+
+ if (actionToLog != null) {
+ PersistableBundle extras = new PersistableBundle();
+ extras.putString(UsageStatsManager.EXTRA_EVENT_CATEGORY, "android.media");
+ extras.putString(UsageStatsManager.EXTRA_EVENT_ACTION, actionToLog);
+ mUsageStatsManagerInternal.reportUserInteractionEvent(
+ packageName, record.getUserId(), extras);
+ }
+ }
+
void tempAllowlistTargetPkgIfPossible(int targetUid, String targetPackage,
int callingPid, int callingUid, String callingPackage, String reason) {
final long token = Binder.clearCallingIdentity();
diff --git a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
index 978f468..bbb19e3 100644
--- a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
+++ b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
@@ -35,6 +35,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManagerInternal;
+import android.app.ActivityOptions.LaunchCookie;
import android.app.AppOpsManager;
import android.app.IProcessObserver;
import android.app.compat.CompatChanges;
@@ -548,8 +549,11 @@
DEFAULT_DISPLAY));
break;
case RECORD_CONTENT_TASK:
- setReviewedConsentSessionLocked(ContentRecordingSession.createTaskSession(
- mProjectionGrant.getLaunchCookie()));
+ IBinder taskWindowContainerToken =
+ mProjectionGrant.getLaunchCookie() == null ? null
+ : mProjectionGrant.getLaunchCookie().binder;
+ setReviewedConsentSessionLocked(
+ ContentRecordingSession.createTaskSession(taskWindowContainerToken));
break;
}
}
@@ -973,7 +977,7 @@
private IBinder mToken;
private IBinder.DeathRecipient mDeathEater;
private boolean mRestoreSystemAlertWindow;
- private IBinder mLaunchCookie = null;
+ private LaunchCookie mLaunchCookie = null;
// Values for tracking token validity.
// Timeout value to compare creation time against.
@@ -1186,14 +1190,14 @@
@android.annotation.EnforcePermission(android.Manifest.permission.MANAGE_MEDIA_PROJECTION)
@Override // Binder call
- public void setLaunchCookie(IBinder launchCookie) {
+ public void setLaunchCookie(LaunchCookie launchCookie) {
setLaunchCookie_enforcePermission();
mLaunchCookie = launchCookie;
}
@android.annotation.EnforcePermission(android.Manifest.permission.MANAGE_MEDIA_PROJECTION)
@Override // Binder call
- public IBinder getLaunchCookie() {
+ public LaunchCookie getLaunchCookie() {
getLaunchCookie_enforcePermission();
return mLaunchCookie;
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 425659e..4da2cc9 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -10869,6 +10869,7 @@
ArrayList<Notification.Action> smartActions = record.getSystemGeneratedSmartActions();
ArrayList<CharSequence> smartReplies = record.getSmartReplies();
if (redactSensitiveNotificationsFromUntrustedListeners()
+ && info != null
&& !mListeners.isUidTrusted(info.uid)
&& mListeners.hasSensitiveContent(record)) {
smartActions = null;
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 923be56d..fb95632 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -840,9 +840,13 @@
&& !PACKAGE_ANDROID.equals(ruleToRemove.pkg)) {
String deletedKey = ZenModeConfig.deletedRuleKey(ruleToRemove);
if (deletedKey != null) {
- ruleToRemove.deletionInstant = Instant.now(mClock);
+ ZenRule deletedRule = ruleToRemove.copy();
+ deletedRule.deletionInstant = Instant.now(mClock);
+ // If the rule is restored it shouldn't be active (or snoozed).
+ deletedRule.snoozing = false;
+ deletedRule.condition = null;
// Overwrites a previously-deleted rule with the same conditionId, but that's okay.
- config.deletedRules.put(deletedKey, ruleToRemove);
+ config.deletedRules.put(deletedKey, deletedRule);
}
}
}
diff --git a/services/core/java/com/android/server/pm/AppsFilterBase.java b/services/core/java/com/android/server/pm/AppsFilterBase.java
index a5bc2c3..98b7c96 100644
--- a/services/core/java/com/android/server/pm/AppsFilterBase.java
+++ b/services/core/java/com/android/server/pm/AppsFilterBase.java
@@ -24,6 +24,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.content.pm.Flags;
import android.content.pm.SigningDetails;
import android.os.Binder;
import android.os.Handler;
@@ -318,6 +319,11 @@
existingSettings.untrackedStorage());
}
+ private static boolean isQueryableBySdkSandbox(int callingUid, int targetUid) {
+ return Flags.allowSdkSandboxQueryIntentActivities()
+ && targetUid == Process.getAppUidForSdkSandboxUid(callingUid);
+ }
+
/**
* See
* {@link AppsFilterSnapshot#shouldFilterApplication(PackageDataSnapshot, int, Object,
@@ -338,9 +344,11 @@
} else if (Process.isSdkSandboxUid(callingAppId)) {
final int targetAppId = targetPkgSetting.getAppId();
final int targetUid = UserHandle.getUid(userId, targetAppId);
- // we only allow sdk sandbox processes access to forcequeryable packages
+ // we only allow sdk sandbox processes access to forcequeryable packages or
+ // if the target app is the sandbox's client app
return !isForceQueryable(targetPkgSetting.getAppId())
- && !isImplicitlyQueryable(callingUid, targetUid);
+ && !isImplicitlyQueryable(callingUid, targetUid)
+ && !isQueryableBySdkSandbox(callingUid, targetUid);
}
// use cache
if (mCacheReady && mCacheEnabled) {
diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java
index ada79ae..e70c5ea 100644
--- a/services/core/java/com/android/server/pm/InstallPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java
@@ -1049,6 +1049,18 @@
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
+ if (Flags.improveInstallFreeze()) {
+ // Postpone freezer until after reconcile
+ for (ReconciledPackage reconciledPkg : reconciledPackages) {
+ InstallRequest installRequest = reconciledPkg.mInstallRequest;
+ String packageName = installRequest.getParsedPackage().getPackageName();
+ PackageFreezer freezer = freezePackageForInstall(packageName,
+ UserHandle.USER_ALL, installRequest.getInstallFlags(),
+ "installPackageLI", ApplicationExitInfo.REASON_PACKAGE_UPDATED,
+ installRequest);
+ installRequest.setFreezer(freezer);
+ }
+ }
try {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "commitPackages");
commitPackagesLocked(reconciledPackages, mPm.mUserManager.getUserIds());
@@ -1613,9 +1625,12 @@
parsedPackage.setBaseApkPath(request.getApexInfo().modulePath);
}
- final PackageFreezer freezer =
- freezePackageForInstall(pkgName, UserHandle.USER_ALL, installFlags,
- "installPackageLI", ApplicationExitInfo.REASON_PACKAGE_UPDATED, request);
+ PackageFreezer freezer = null;
+ if (!Flags.improveInstallFreeze()) {
+ freezer = freezePackageForInstall(pkgName, UserHandle.USER_ALL, installFlags,
+ "installPackageLI", ApplicationExitInfo.REASON_PACKAGE_UPDATED, request);
+ }
+
boolean shouldCloseFreezerBeforeReturn = true;
try {
@@ -1865,9 +1880,11 @@
oldPackageState, parsedPackage, archivedPackage,
replace /* clearCodeCache */, sysPkg, ps, disabledPs);
} finally {
- request.setFreezer(freezer);
- if (shouldCloseFreezerBeforeReturn) {
- freezer.close();
+ if (freezer != null) {
+ request.setFreezer(freezer);
+ if (shouldCloseFreezerBeforeReturn) {
+ freezer.close();
+ }
}
}
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 135bd4f..9617098 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -7807,7 +7807,8 @@
mResolveActivity.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
mResolveActivity.flags = ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS
| ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS
- | ActivityInfo.FLAG_CAN_DISPLAY_ON_REMOTE_DEVICES;
+ | ActivityInfo.FLAG_CAN_DISPLAY_ON_REMOTE_DEVICES
+ | ActivityInfo.FLAG_HARDWARE_ACCELERATED;
mResolveActivity.theme = 0;
mResolveActivity.exported = true;
mResolveActivity.enabled = true;
@@ -7841,7 +7842,8 @@
mResolveActivity.documentLaunchMode = ActivityInfo.DOCUMENT_LAUNCH_NEVER;
mResolveActivity.flags = ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS
| ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY
- | ActivityInfo.FLAG_CAN_DISPLAY_ON_REMOTE_DEVICES;
+ | ActivityInfo.FLAG_CAN_DISPLAY_ON_REMOTE_DEVICES
+ | ActivityInfo.FLAG_HARDWARE_ACCELERATED;
mResolveActivity.theme = R.style.Theme_Material_Dialog_Alert;
mResolveActivity.exported = true;
mResolveActivity.enabled = true;
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index a97652c..7cf1d33 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -517,15 +517,6 @@
@Watched(manual = true)
private final AppIdSettingMap mAppIds;
- // For reading/writing settings file.
- @Watched
- private final WatchedArrayList<Signature> mPastSignatures;
- private final SnapshotCache<WatchedArrayList<Signature>> mPastSignaturesSnapshot;
-
- @Watched
- private final WatchedArrayMap<Long, Integer> mKeySetRefs;
- private final SnapshotCache<WatchedArrayMap<Long, Integer>> mKeySetRefsSnapshot;
-
// Packages that have been renamed since they were first installed.
// Keys are the new names of the packages, values are the original
// names. The packages appear everywhere else under their original
@@ -613,8 +604,6 @@
mNextAppLinkGeneration.registerObserver(mObserver);
mPendingDefaultBrowser.registerObserver(mObserver);
mPendingPackages.registerObserver(mObserver);
- mPastSignatures.registerObserver(mObserver);
- mKeySetRefs.registerObserver(mObserver);
}
// CONSTRUCTOR
@@ -641,12 +630,6 @@
mCrossProfileIntentResolversSnapshot = new SnapshotCache.Auto<>(
mCrossProfileIntentResolvers, mCrossProfileIntentResolvers,
"Settings.mCrossProfileIntentResolvers");
- mPastSignatures = new WatchedArrayList<>();
- mPastSignaturesSnapshot = new SnapshotCache.Auto<>(mPastSignatures, mPastSignatures,
- "Settings.mPastSignatures");
- mKeySetRefs = new WatchedArrayMap<>();
- mKeySetRefsSnapshot = new SnapshotCache.Auto<>(mKeySetRefs, mKeySetRefs,
- "Settings.mKeySetRefs");
mPendingPackages = new WatchedArrayList<>();
mPendingPackagesSnapshot = new SnapshotCache.Auto<>(mPendingPackages, mPendingPackages,
"Settings.mPendingPackages");
@@ -702,12 +685,6 @@
mCrossProfileIntentResolversSnapshot = new SnapshotCache.Auto<>(
mCrossProfileIntentResolvers, mCrossProfileIntentResolvers,
"Settings.mCrossProfileIntentResolvers");
- mPastSignatures = new WatchedArrayList<>();
- mPastSignaturesSnapshot = new SnapshotCache.Auto<>(mPastSignatures, mPastSignatures,
- "Settings.mPastSignatures");
- mKeySetRefs = new WatchedArrayMap<>();
- mKeySetRefsSnapshot = new SnapshotCache.Auto<>(mKeySetRefs, mKeySetRefs,
- "Settings.mKeySetRefs");
mPendingPackages = new WatchedArrayList<>();
mPendingPackagesSnapshot = new SnapshotCache.Auto<>(mPendingPackages, mPendingPackages,
"Settings.mPendingPackages");
@@ -799,11 +776,6 @@
mSharedUsers.snapshot(r.mSharedUsers);
mAppIds = r.mAppIds.snapshot();
- mPastSignatures = r.mPastSignaturesSnapshot.snapshot();
- mPastSignaturesSnapshot = new SnapshotCache.Sealed<>();
- mKeySetRefs = r.mKeySetRefsSnapshot.snapshot();
- mKeySetRefsSnapshot = new SnapshotCache.Sealed<>();
-
mRenamedPackages.snapshot(r.mRenamedPackages);
mNextAppLinkGeneration.snapshot(r.mNextAppLinkGeneration);
mPendingDefaultBrowser.snapshot(r.mPendingDefaultBrowser);
@@ -2755,7 +2727,7 @@
// right time.
invalidatePackageCache();
- mPastSignatures.clear();
+ ArrayList<Signature> writtenSignatures = new ArrayList<>();
try (ResilientAtomicFile atomicFile = getSettingsFile()) {
FileOutputStream str = null;
@@ -2803,7 +2775,7 @@
// load
continue;
}
- writePackageLPr(serializer, pkg);
+ writePackageLPr(serializer, writtenSignatures, pkg);
}
for (final PackageSetting pkg : mDisabledSysPackages.values()) {
@@ -2819,7 +2791,7 @@
serializer.startTag(null, "shared-user");
serializer.attribute(null, ATTR_NAME, usr.name);
serializer.attributeInt(null, "userId", usr.mAppId);
- usr.signatures.writeXml(serializer, "sigs", mPastSignatures.untrackedStorage());
+ usr.signatures.writeXml(serializer, "sigs", writtenSignatures);
serializer.endTag(null, "shared-user");
}
@@ -2859,6 +2831,7 @@
}
}
}
+
//Debug.stopMethodTracing();
}
@@ -3159,7 +3132,8 @@
serializer.endTag(null, "updated-package");
}
- void writePackageLPr(TypedXmlSerializer serializer, final PackageSetting pkg)
+ void writePackageLPr(TypedXmlSerializer serializer, ArrayList<Signature> writtenSignatures,
+ PackageSetting pkg)
throws java.io.IOException {
serializer.startTag(null, "package");
serializer.attribute(null, ATTR_NAME, pkg.getPackageName());
@@ -3259,11 +3233,11 @@
writeUsesStaticLibLPw(serializer, pkg.getUsesStaticLibraries(),
pkg.getUsesStaticLibrariesVersions());
- pkg.getSignatures().writeXml(serializer, "sigs", mPastSignatures.untrackedStorage());
+ pkg.getSignatures().writeXml(serializer, "sigs", writtenSignatures);
if (installSource.mInitiatingPackageSignatures != null) {
installSource.mInitiatingPackageSignatures.writeXml(
- serializer, "install-initiator-sigs", mPastSignatures.untrackedStorage());
+ serializer, "install-initiator-sigs", writtenSignatures);
}
writeSigningKeySetLPr(serializer, pkg.getKeySetData());
@@ -3305,11 +3279,12 @@
boolean readSettingsLPw(@NonNull Computer computer, @NonNull List<UserInfo> users,
ArrayMap<String, Long> originalFirstInstallTimes) {
mPendingPackages.clear();
- mPastSignatures.clear();
- mKeySetRefs.clear();
mInstallerPackages.clear();
originalFirstInstallTimes.clear();
+ ArrayMap<Long, Integer> keySetRefs = new ArrayMap<>();
+ ArrayList<Signature> readSignatures = new ArrayList<>();
+
try (ResilientAtomicFile atomicFile = getSettingsFile()) {
FileInputStream str = null;
try {
@@ -3346,13 +3321,14 @@
String tagName = parser.getName();
if (tagName.equals("package")) {
- readPackageLPw(parser, users, originalFirstInstallTimes);
+ readPackageLPw(parser, readSignatures, keySetRefs, users,
+ originalFirstInstallTimes);
} else if (tagName.equals("permissions")) {
mPermissions.readPermissions(parser);
} else if (tagName.equals("permission-trees")) {
mPermissions.readPermissionTrees(parser);
} else if (tagName.equals("shared-user")) {
- readSharedUserLPw(parser, users);
+ readSharedUserLPw(parser, readSignatures, users);
} else if (tagName.equals("preferred-packages")) {
// no longer used.
} else if (tagName.equals("preferred-activities")) {
@@ -3412,8 +3388,7 @@
} else if (TAG_READ_EXTERNAL_STORAGE.equals(tagName)) {
// No longer used.
} else if (tagName.equals("keyset-settings")) {
- mKeySetManagerService.readKeySetsLPw(parser,
- mKeySetRefs.untrackedStorage());
+ mKeySetManagerService.readKeySetsLPw(parser, keySetRefs);
} else if (TAG_VERSION.equals(tagName)) {
final String volumeUuid = XmlUtils.readStringAttribute(parser,
ATTR_VOLUME_UUID);
@@ -3437,7 +3412,7 @@
}
str.close();
- } catch (IOException | XmlPullParserException e) {
+ } catch (IOException | XmlPullParserException | ArrayIndexOutOfBoundsException e) {
// Remove corrupted file and retry.
atomicFile.failRead(str, e);
@@ -4007,7 +3982,8 @@
private static final int PRE_M_APP_INFO_FLAG_CANT_SAVE_STATE = 1 << 28;
private static final int PRE_M_APP_INFO_FLAG_PRIVILEGED = 1 << 30;
- private void readPackageLPw(TypedXmlPullParser parser, List<UserInfo> users,
+ private void readPackageLPw(TypedXmlPullParser parser, ArrayList<Signature> readSignatures,
+ ArrayMap<Long, Integer> keySetRefs, List<UserInfo> users,
ArrayMap<String, Long> originalFirstInstallTimes)
throws XmlPullParserException, IOException {
String name = null;
@@ -4282,8 +4258,7 @@
} else if (tagName.equals(TAG_ENABLED_COMPONENTS)) {
readEnabledComponentsLPw(packageSetting, parser, 0);
} else if (tagName.equals("sigs")) {
- packageSetting.getSignatures()
- .readXml(parser,mPastSignatures.untrackedStorage());
+ packageSetting.getSignatures().readXml(parser, readSignatures);
} else if (tagName.equals(TAG_PERMISSIONS)) {
final LegacyPermissionState legacyState;
if (packageSetting.hasSharedUser()) {
@@ -4300,11 +4275,11 @@
}
} else if (tagName.equals("proper-signing-keyset")) {
long id = parser.getAttributeLong(null, "identifier");
- Integer refCt = mKeySetRefs.get(id);
+ Integer refCt = keySetRefs.get(id);
if (refCt != null) {
- mKeySetRefs.put(id, refCt + 1);
+ keySetRefs.put(id, refCt + 1);
} else {
- mKeySetRefs.put(id, 1);
+ keySetRefs.put(id, 1);
}
packageSetting.getKeySetData().setProperSigningKeySet(id);
} else if (tagName.equals("signing-keyset")) {
@@ -4315,16 +4290,16 @@
} else if (tagName.equals("defined-keyset")) {
long id = parser.getAttributeLong(null, "identifier");
String alias = parser.getAttributeValue(null, "alias");
- Integer refCt = mKeySetRefs.get(id);
+ Integer refCt = keySetRefs.get(id);
if (refCt != null) {
- mKeySetRefs.put(id, refCt + 1);
+ keySetRefs.put(id, refCt + 1);
} else {
- mKeySetRefs.put(id, 1);
+ keySetRefs.put(id, 1);
}
packageSetting.getKeySetData().addDefinedKeySet(id, alias);
} else if (tagName.equals("install-initiator-sigs")) {
final PackageSignatures signatures = new PackageSignatures();
- signatures.readXml(parser, mPastSignatures.untrackedStorage());
+ signatures.readXml(parser, readSignatures);
packageSetting.setInstallSource(
packageSetting.getInstallSource()
.setInitiatingPackageSignatures(signatures));
@@ -4497,7 +4472,8 @@
}
}
- private void readSharedUserLPw(TypedXmlPullParser parser, List<UserInfo> users)
+ private void readSharedUserLPw(TypedXmlPullParser parser, ArrayList<Signature> readSignatures,
+ List<UserInfo> users)
throws XmlPullParserException, IOException {
String name = null;
int pkgFlags = 0;
@@ -4539,7 +4515,7 @@
String tagName = parser.getName();
if (tagName.equals("sigs")) {
- su.signatures.readXml(parser, mPastSignatures.untrackedStorage());
+ su.signatures.readXml(parser, readSignatures);
} else if (tagName.equals("perms")) {
readInstallPermissionsLPr(parser, su.getLegacyPermissionState(), users);
} else {
diff --git a/services/core/java/com/android/server/pm/UserTypeFactory.java b/services/core/java/com/android/server/pm/UserTypeFactory.java
index 14db70e..23d0230 100644
--- a/services/core/java/com/android/server/pm/UserTypeFactory.java
+++ b/services/core/java/com/android/server/pm/UserTypeFactory.java
@@ -288,6 +288,28 @@
* configuration.
*/
private static UserTypeDetails.Builder getDefaultTypeProfilePrivate() {
+ UserProperties.Builder userPropertiesBuilder = new UserProperties.Builder()
+ .setStartWithParent(true)
+ .setCredentialShareableWithParent(true)
+ .setAuthAlwaysRequiredToDisableQuietMode(true)
+ .setAllowStoppingUserWithDelayedLocking(true)
+ .setMediaSharedWithParent(false)
+ .setShowInLauncher(UserProperties.SHOW_IN_LAUNCHER_SEPARATE)
+ .setShowInSettings(UserProperties.SHOW_IN_SETTINGS_SEPARATE)
+ .setShowInQuietMode(
+ UserProperties.SHOW_IN_QUIET_MODE_HIDDEN)
+ .setShowInSharingSurfaces(
+ UserProperties.SHOW_IN_SHARING_SURFACES_SEPARATE)
+ .setCrossProfileIntentFilterAccessControl(
+ UserProperties.CROSS_PROFILE_INTENT_FILTER_ACCESS_LEVEL_SYSTEM)
+ .setInheritDevicePolicy(UserProperties.INHERIT_DEVICE_POLICY_FROM_PARENT)
+ .setCrossProfileContentSharingStrategy(
+ UserProperties.CROSS_PROFILE_CONTENT_SHARING_DELEGATE_FROM_PARENT);
+ if (android.multiuser.Flags.supportHidingProfiles()) {
+ userPropertiesBuilder.setProfileApiVisibility(
+ UserProperties.PROFILE_API_VISIBILITY_HIDDEN);
+ }
+
return new UserTypeDetails.Builder()
.setName(USER_TYPE_PROFILE_PRIVATE)
.setBaseType(FLAG_PROFILE)
@@ -306,23 +328,7 @@
.setDarkThemeBadgeColors(
R.color.white)
.setDefaultRestrictions(getDefaultProfileRestrictions())
- .setDefaultUserProperties(new UserProperties.Builder()
- .setStartWithParent(true)
- .setCredentialShareableWithParent(true)
- .setAuthAlwaysRequiredToDisableQuietMode(true)
- .setAllowStoppingUserWithDelayedLocking(true)
- .setMediaSharedWithParent(false)
- .setShowInLauncher(UserProperties.SHOW_IN_LAUNCHER_SEPARATE)
- .setShowInSettings(UserProperties.SHOW_IN_SETTINGS_SEPARATE)
- .setShowInQuietMode(
- UserProperties.SHOW_IN_QUIET_MODE_HIDDEN)
- .setShowInSharingSurfaces(
- UserProperties.SHOW_IN_SHARING_SURFACES_SEPARATE)
- .setCrossProfileIntentFilterAccessControl(
- UserProperties.CROSS_PROFILE_INTENT_FILTER_ACCESS_LEVEL_SYSTEM)
- .setInheritDevicePolicy(UserProperties.INHERIT_DEVICE_POLICY_FROM_PARENT)
- .setCrossProfileContentSharingStrategy(
- UserProperties.CROSS_PROFILE_CONTENT_SHARING_DELEGATE_FROM_PARENT));
+ .setDefaultUserProperties(userPropertiesBuilder);
}
/**
diff --git a/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
index d0fe964..6ed2d31 100644
--- a/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
+++ b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
@@ -421,6 +421,11 @@
if (ai.isArchived) {
ai.nonLocalizedLabel = state.getArchiveState().getActivityInfos().get(0).getTitle();
}
+ if (!state.isInstalled() && !state.dataExists()
+ && android.content.pm.Flags.nullableDataDir()) {
+ // The data dir has been deleted
+ ai.dataDir = null;
+ }
}
@Nullable
diff --git a/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java b/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
index 09b19e6..25e749f 100644
--- a/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
+++ b/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
@@ -138,6 +138,7 @@
import com.android.modules.utils.TypedXmlPullParser;
import com.android.modules.utils.TypedXmlSerializer;
import com.android.net.module.util.NetworkCapabilitiesUtils;
+import com.android.server.power.optimization.Flags;
import com.android.server.power.stats.SystemServerCpuThreadReader.SystemServiceCpuThreadTimes;
import libcore.util.EmptyArray;
@@ -185,7 +186,8 @@
// TODO: remove "tcp" from network methods, since we measure total stats.
// Current on-disk Parcel version. Must be updated when the format of the parcelable changes
- public static final int VERSION = 214;
+ public static final int VERSION =
+ !Flags.disableSystemServicePowerAttr() ? 214 : 215;
// The maximum number of names wakelocks we will keep track of
// per uid; once the limit is reached, we batch the remaining wakelocks
@@ -1753,7 +1755,9 @@
mCpuUidActiveTimeReader = new KernelCpuUidActiveTimeReader(true, mClock);
mCpuUidClusterTimeReader = new KernelCpuUidClusterTimeReader(true, mClock);
mKernelWakelockReader = new KernelWakelockReader();
- mSystemServerCpuThreadReader = SystemServerCpuThreadReader.create();
+ if (!Flags.disableSystemServicePowerAttr()) {
+ mSystemServerCpuThreadReader = SystemServerCpuThreadReader.create();
+ }
mKernelMemoryBandwidthStats = new KernelMemoryBandwidthStats();
mTmpRailStats = new RailStats();
}
@@ -11459,7 +11463,7 @@
@Override
public BatteryStatsHistoryIterator iterateBatteryStatsHistory(long startTimeMs,
long endTimeMs) {
- return mHistory.copy().iterate(startTimeMs, endTimeMs);
+ return mHistory.iterate(startTimeMs, endTimeMs);
}
@Override
@@ -11702,7 +11706,9 @@
EnergyConsumerStats.resetIfNotNull(mGlobalEnergyConsumerStats);
- resetIfNotNull(mBinderThreadCpuTimesUs, false, elapsedRealtimeUs);
+ if (!Flags.disableSystemServicePowerAttr()) {
+ resetIfNotNull(mBinderThreadCpuTimesUs, false, elapsedRealtimeUs);
+ }
mNumAllUidCpuTimeReads = 0;
mNumUidsRemoved = 0;
@@ -13676,7 +13682,9 @@
mKernelCpuSpeedReaders[i].readDelta();
}
}
- mSystemServerCpuThreadReader.readDelta();
+ if (!Flags.disableSystemServicePowerAttr()) {
+ mSystemServerCpuThreadReader.readDelta();
+ }
return;
}
@@ -15696,23 +15704,25 @@
}
}
- updateSystemServiceCallStats();
- if (mBinderThreadCpuTimesUs != null) {
- pw.println("Per UID System server binder time in ms:");
- long[] systemServiceTimeAtCpuSpeeds = getSystemServiceTimeAtCpuSpeeds();
- for (int i = 0; i < size; i++) {
- int u = mUidStats.keyAt(i);
- Uid uid = mUidStats.get(u);
- double proportionalSystemServiceUsage = uid.getProportionalSystemServiceUsage();
- long timeUs = 0;
- for (int j = systemServiceTimeAtCpuSpeeds.length - 1; j >= 0; j--) {
- timeUs += systemServiceTimeAtCpuSpeeds[j] * proportionalSystemServiceUsage;
- }
+ if (!Flags.disableSystemServicePowerAttr()) {
+ updateSystemServiceCallStats();
+ if (mBinderThreadCpuTimesUs != null) {
+ pw.println("Per UID System server binder time in ms:");
+ long[] systemServiceTimeAtCpuSpeeds = getSystemServiceTimeAtCpuSpeeds();
+ for (int i = 0; i < size; i++) {
+ int u = mUidStats.keyAt(i);
+ Uid uid = mUidStats.get(u);
+ double proportionalSystemServiceUsage = uid.getProportionalSystemServiceUsage();
+ long timeUs = 0;
+ for (int j = systemServiceTimeAtCpuSpeeds.length - 1; j >= 0; j--) {
+ timeUs += systemServiceTimeAtCpuSpeeds[j] * proportionalSystemServiceUsage;
+ }
- pw.print(" ");
- pw.print(u);
- pw.print(": ");
- pw.println(timeUs / 1000);
+ pw.print(" ");
+ pw.print(u);
+ pw.print(": ");
+ pw.println(timeUs / 1000);
+ }
}
}
}
@@ -16428,8 +16438,10 @@
}
}
- mBinderThreadCpuTimesUs =
- LongSamplingCounterArray.readSummaryFromParcelLocked(in, mOnBatteryTimeBase);
+ if (!Flags.disableSystemServicePowerAttr()) {
+ mBinderThreadCpuTimesUs =
+ LongSamplingCounterArray.readSummaryFromParcelLocked(in, mOnBatteryTimeBase);
+ }
}
/**
@@ -16973,7 +16985,9 @@
}
}
- LongSamplingCounterArray.writeSummaryToParcelLocked(out, mBinderThreadCpuTimesUs);
+ if (!Flags.disableSystemServicePowerAttr()) {
+ LongSamplingCounterArray.writeSummaryToParcelLocked(out, mBinderThreadCpuTimesUs);
+ }
}
@GuardedBy("this")
@@ -16985,7 +16999,9 @@
// if we had originally pulled a time before the RTC was set.
getStartClockTime();
- updateSystemServiceCallStats();
+ if (!Flags.disableSystemServicePowerAttr()) {
+ updateSystemServiceCallStats();
+ }
}
@GuardedBy("this")
diff --git a/services/core/java/com/android/server/power/stats/BatteryUsageStatsProvider.java b/services/core/java/com/android/server/power/stats/BatteryUsageStatsProvider.java
index c3221e4..30b80ae 100644
--- a/services/core/java/com/android/server/power/stats/BatteryUsageStatsProvider.java
+++ b/services/core/java/com/android/server/power/stats/BatteryUsageStatsProvider.java
@@ -96,11 +96,13 @@
mPowerCalculators.add(new CustomEnergyConsumerPowerCalculator(mPowerProfile));
mPowerCalculators.add(new UserPowerCalculator());
- // It is important that SystemServicePowerCalculator be applied last,
- // because it re-attributes some of the power estimated by the other
- // calculators.
- mPowerCalculators.add(
- new SystemServicePowerCalculator(mCpuScalingPolicies, mPowerProfile));
+ if (!com.android.server.power.optimization.Flags.disableSystemServicePowerAttr()) {
+ // It is important that SystemServicePowerCalculator be applied last,
+ // because it re-attributes some of the power estimated by the other
+ // calculators.
+ mPowerCalculators.add(
+ new SystemServicePowerCalculator(mCpuScalingPolicies, mPowerProfile));
+ }
}
}
return mPowerCalculators;
diff --git a/services/core/java/com/android/server/power/stats/PowerStatsAggregator.java b/services/core/java/com/android/server/power/stats/PowerStatsAggregator.java
index cd3db36..ba4c127 100644
--- a/services/core/java/com/android/server/power/stats/PowerStatsAggregator.java
+++ b/services/core/java/com/android/server/power/stats/PowerStatsAggregator.java
@@ -74,8 +74,7 @@
boolean clockUpdateAdded = false;
long baseTime = startTimeMs > 0 ? startTimeMs : UNINITIALIZED;
long lastTime = 0;
- try (BatteryStatsHistoryIterator iterator =
- mHistory.copy().iterate(startTimeMs, endTimeMs)) {
+ try (BatteryStatsHistoryIterator iterator = mHistory.iterate(startTimeMs, endTimeMs)) {
while (iterator.hasNext()) {
BatteryStats.HistoryItem item = iterator.next();
diff --git a/services/core/java/com/android/server/power/stats/flags.aconfig b/services/core/java/com/android/server/power/stats/flags.aconfig
index 0f13571..6546646 100644
--- a/services/core/java/com/android/server/power/stats/flags.aconfig
+++ b/services/core/java/com/android/server/power/stats/flags.aconfig
@@ -13,3 +13,11 @@
description: "Feature flag for streamlined battery stats"
bug: "285646152"
}
+
+flag {
+ name: "disable_system_service_power_attr"
+ namespace: "backstage_power"
+ description: "Deprecation of system service power re-attribution"
+ bug: "311793616"
+ is_fixed_read_only: true
+}
diff --git a/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java b/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java
index a4dbce6..3c0547e 100644
--- a/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java
+++ b/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java
@@ -527,6 +527,7 @@
if (DEBUG) Slog.d(TAG, "rebootRecoveryWithCommand: [" + command + "]");
synchronized (sRequestLock) {
if (!setupOrClearBcb(true, command)) {
+ Slog.e(TAG, "rebootRecoveryWithCommand failed to setup BCB");
return;
}
diff --git a/services/core/java/com/android/server/recoverysystem/RecoverySystemShellCommand.java b/services/core/java/com/android/server/recoverysystem/RecoverySystemShellCommand.java
index 141d4dc..9ee9b14 100644
--- a/services/core/java/com/android/server/recoverysystem/RecoverySystemShellCommand.java
+++ b/services/core/java/com/android/server/recoverysystem/RecoverySystemShellCommand.java
@@ -48,6 +48,8 @@
return isLskfCaptured();
case "reboot-and-apply":
return rebootAndApply();
+ case "wipe":
+ return wipe();
default:
return handleDefaultCommands(cmd);
}
@@ -58,6 +60,18 @@
}
}
+ private int wipe() throws RemoteException {
+ PrintWriter pw = getOutPrintWriter();
+ String newFsType = getNextArg();
+ String command = "--wipe_data";
+ if (newFsType != null && !newFsType.isEmpty()) {
+ command += "\n--reformat_data=" + newFsType;
+ }
+ pw.println("Rebooting into recovery with " + command.replaceAll("\n", " "));
+ mService.rebootRecoveryWithCommand(command);
+ return 0;
+ }
+
private int requestLskf() throws RemoteException {
String packageName = getNextArgRequired();
boolean success = mService.requestLskf(packageName, null);
@@ -104,5 +118,6 @@
pw.println(" clear-lskf");
pw.println(" is-lskf-captured <package_name>");
pw.println(" reboot-and-apply <package_name> <reason>");
+ pw.println(" wipe <new filesystem type ext4/f2fs>");
}
}
diff --git a/services/core/java/com/android/server/servicewatcher/CurrentUserServiceSupplier.java b/services/core/java/com/android/server/servicewatcher/CurrentUserServiceSupplier.java
index 6677e7e..1526230 100644
--- a/services/core/java/com/android/server/servicewatcher/CurrentUserServiceSupplier.java
+++ b/services/core/java/com/android/server/servicewatcher/CurrentUserServiceSupplier.java
@@ -36,10 +36,12 @@
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.content.res.Resources;
+import android.location.flags.Flags;
import android.os.Bundle;
import android.os.Process;
import android.os.UserHandle;
import android.util.Log;
+import android.util.TypedValue;
import com.android.internal.util.Preconditions;
import com.android.server.FgThread;
@@ -70,6 +72,10 @@
private static final String EXTRA_SERVICE_VERSION = "serviceVersion";
private static final String EXTRA_SERVICE_IS_MULTIUSER = "serviceIsMultiuser";
+ // a package value that will never match against any package (we can't use null since this will
+ // match against any package).
+ private static final String NO_MATCH_PACKAGE = "";
+
private static final Comparator<BoundServiceInfo> sBoundServiceInfoComparator = (o1, o2) -> {
if (o1 == o2) {
return 0;
@@ -196,7 +202,19 @@
Resources resources = context.getResources();
boolean enableOverlay = resources.getBoolean(enableOverlayResId);
if (!enableOverlay) {
- return resources.getString(nonOverlayPackageResId);
+ if (Flags.fixServiceWatcher()) {
+ // we don't use getText() or similar because it won't return null values
+ TypedValue out = new TypedValue();
+ resources.getValue(nonOverlayPackageResId, out, true);
+ CharSequence explicitPackage = out.coerceToString();
+ if (explicitPackage == null) {
+ return NO_MATCH_PACKAGE;
+ } else {
+ return explicitPackage.toString();
+ }
+ } else {
+ return resources.getString(nonOverlayPackageResId);
+ }
} else {
return null;
}
@@ -233,6 +251,10 @@
@Override
public boolean hasMatchingService() {
+ if (Flags.fixServiceWatcher() && NO_MATCH_PACKAGE.equals(mIntent.getPackage())) {
+ return false;
+ }
+
int intentQueryFlags = MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE;
if (mMatchSystemAppsOnly) {
intentQueryFlags |= MATCH_SYSTEM_ONLY;
@@ -268,6 +290,10 @@
@Override
public BoundServiceInfo getServiceInfo() {
+ if (Flags.fixServiceWatcher() && NO_MATCH_PACKAGE.equals(mIntent.getPackage())) {
+ return null;
+ }
+
BoundServiceInfo bestServiceInfo = null;
// only allow services in the correct direct boot state to match
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 285bcc3..0ffd002 100644
--- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
@@ -2058,7 +2058,8 @@
}
private void registerCpuCyclesPerThreadGroupCluster() {
- if (KernelCpuBpfTracking.isSupported()) {
+ if (KernelCpuBpfTracking.isSupported()
+ && !com.android.server.power.optimization.Flags.disableSystemServicePowerAttr()) {
int tagId = FrameworkStatsLog.CPU_CYCLES_PER_THREAD_GROUP_CLUSTER;
PullAtomMetadata metadata = new PullAtomMetadata.Builder()
.setAdditiveFields(new int[]{3, 4})
@@ -2073,6 +2074,10 @@
}
int pullCpuCyclesPerThreadGroupCluster(int atomTag, List<StatsEvent> pulledData) {
+ if (com.android.server.power.optimization.Flags.disableSystemServicePowerAttr()) {
+ return StatsManager.PULL_SKIP;
+ }
+
SystemServiceCpuThreadTimes times = LocalServices.getService(BatteryStatsInternal.class)
.getSystemServiceCpuThreadTimes();
if (times == null) {
diff --git a/services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java b/services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java
index b6d0ca1..eacd3f8 100644
--- a/services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java
+++ b/services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java
@@ -4152,6 +4152,25 @@
}
@Override
+ public void onRequestSigning2(String id, String algorithm, String host,
+ int port, byte[] data) {
+ synchronized (mLock) {
+ if (DEBUG) {
+ Slogf.d(TAG, "onRequestSigning");
+ }
+ if (mSessionState.mSession == null || mSessionState.mClient == null) {
+ return;
+ }
+ try {
+ mSessionState.mClient.onRequestSigning2(
+ id, algorithm, host, port, data, mSessionState.mSeq);
+ } catch (RemoteException e) {
+ Slogf.e(TAG, "error in onRequestSigning", e);
+ }
+ }
+ }
+
+ @Override
public void onRequestCertificate(String host, int port) {
synchronized (mLock) {
if (DEBUG) {
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index f2d9bf8..fa8c35a 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -1540,16 +1540,12 @@
private static final boolean DEBUG = false;
- private final List<AccessibilityWindow> mTempA11yWindows = new ArrayList<>();
-
private final Set<IBinder> mTempBinderSet = new ArraySet<>();
private final Point mTempPoint = new Point();
private final Region mTempRegion = new Region();
- private final Region mTempRegion1 = new Region();
-
private final Region mTempRegion2 = new Region();
private final WindowManagerService mService;
@@ -1617,7 +1613,8 @@
Slog.i(LOG_TAG, "computeChangedWindows()");
}
- List<WindowInfo> windows = new ArrayList<>();
+ final List<WindowInfo> windows = new ArrayList<>();
+ final List<AccessibilityWindow> visibleWindows = new ArrayList<>();
final int topFocusedDisplayId;
IBinder topFocusedWindowToken = null;
@@ -1652,7 +1649,6 @@
Region unaccountedSpace = mTempRegion;
unaccountedSpace.set(0, 0, screenWidth, screenHeight);
- final List<AccessibilityWindow> visibleWindows = mTempA11yWindows;
mA11yWindowsPopulator.populateVisibleWindowsOnScreenLocked(
mDisplayId, visibleWindows);
Set<IBinder> addedWindows = mTempBinderSet;
@@ -1709,7 +1705,6 @@
}
}
- visibleWindows.clear();
addedWindows.clear();
// Gets the top focused display Id and window token for supporting multi-display.
@@ -1720,7 +1715,9 @@
topFocusedWindowToken, windows);
// Recycle the windows as we do not need them.
- clearAndRecycleWindows(windows);
+ for (final AccessibilityWindowsPopulator.AccessibilityWindow window : visibleWindows) {
+ window.getWindowInfo().recycle();
+ }
mInitialized = true;
}
@@ -1802,13 +1799,6 @@
tokenOut.add(window.token);
}
- private static void clearAndRecycleWindows(List<WindowInfo> windows) {
- final int windowCount = windows.size();
- for (int i = windowCount - 1; i >= 0; i--) {
- windows.remove(i).recycle();
- }
- }
-
private static boolean isReportedWindowType(int windowType) {
return (windowType != WindowManager.LayoutParams.TYPE_WALLPAPER
&& windowType != WindowManager.LayoutParams.TYPE_BOOT_PROGRESS
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index d9fa01e..03d55d9 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -53,6 +53,7 @@
import static android.app.admin.DevicePolicyResources.Drawables.Source.PROFILE_SWITCH_ANIMATION;
import static android.app.admin.DevicePolicyResources.Drawables.Style.OUTLINE;
import static android.app.admin.DevicePolicyResources.Drawables.WORK_PROFILE_ICON;
+import static android.content.Context.CONTEXT_RESTRICTED;
import static android.content.Intent.ACTION_MAIN;
import static android.content.Intent.CATEGORY_HOME;
import static android.content.Intent.CATEGORY_LAUNCHER;
@@ -2231,7 +2232,17 @@
mOptInOnBackInvoked = WindowOnBackInvokedDispatcher
.isOnBackInvokedCallbackEnabled(info, info.applicationInfo,
- () -> ent != null ? ent.array : null, false);
+ () -> {
+ Context appContext = null;
+ try {
+ appContext = mAtmService.mContext.createPackageContextAsUser(
+ info.packageName, CONTEXT_RESTRICTED,
+ UserHandle.of(mUserId));
+ appContext.setTheme(theme);
+ } catch (PackageManager.NameNotFoundException ignore) {
+ }
+ return appContext;
+ });
}
/**
diff --git a/services/core/java/com/android/server/wm/ActivitySnapshotController.java b/services/core/java/com/android/server/wm/ActivitySnapshotController.java
index a692167..1f013b9 100644
--- a/services/core/java/com/android/server/wm/ActivitySnapshotController.java
+++ b/services/core/java/com/android/server/wm/ActivitySnapshotController.java
@@ -31,8 +31,6 @@
import android.window.TaskSnapshot;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.server.LocalServices;
-import com.android.server.pm.UserManagerInternal;
import com.android.server.wm.BaseAppSnapshotPersister.PersistInfoProvider;
import com.android.window.flags.Flags;
@@ -163,18 +161,12 @@
private void cleanUpUserFiles(int userId) {
synchronized (mSnapshotPersistQueue.getLock()) {
mSnapshotPersistQueue.sendToQueueLocked(
- new SnapshotPersistQueue.WriteQueueItem(mPersistInfoProvider) {
- @Override
- boolean isReady() {
- final UserManagerInternal mUserManagerInternal =
- LocalServices.getService(UserManagerInternal.class);
- return mUserManagerInternal.isUserUnlocked(userId);
- }
+ new SnapshotPersistQueue.WriteQueueItem(mPersistInfoProvider, userId) {
@Override
void write() {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "cleanUpUserFiles");
- final File file = mPersistInfoProvider.getDirectory(userId);
+ final File file = mPersistInfoProvider.getDirectory(mUserId);
if (file.exists()) {
final File[] contents = file.listFiles();
if (contents != null) {
@@ -263,15 +255,13 @@
class LoadActivitySnapshotItem extends SnapshotPersistQueue.WriteQueueItem {
private final int mCode;
- private final int mUserId;
private final ActivityRecord[] mActivities;
LoadActivitySnapshotItem(@NonNull ActivityRecord[] activities, int code, int userId,
@NonNull PersistInfoProvider persistInfoProvider) {
- super(persistInfoProvider);
+ super(persistInfoProvider, userId);
mActivities = activities;
mCode = code;
- mUserId = userId;
}
@Override
@@ -305,6 +295,11 @@
return mCode == other.mCode && mUserId == other.mUserId
&& mPersistInfoProvider == other.mPersistInfoProvider;
}
+
+ @Override
+ public String toString() {
+ return "LoadActivitySnapshotItem{code=" + mCode + ", UserId=" + mUserId + "}";
+ }
}
void loadActivitySnapshot() {
@@ -714,24 +709,9 @@
}
removeTargets.add(usf);
}
- removeSnapshotFiles(removeTargets);
- }
-
- private void removeSnapshotFiles(@NonNull ArrayList<UserSavedFile> files) {
- synchronized (mSnapshotPersistQueue.getLock()) {
- mSnapshotPersistQueue.sendToQueueLocked(
- new SnapshotPersistQueue.WriteQueueItem(mPersistInfoProvider) {
- @Override
- void write() {
- Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "activity_remove_files");
- for (int i = files.size() - 1; i >= 0; --i) {
- final UserSavedFile usf = files.get(i);
- mSnapshotPersistQueue.deleteSnapshot(
- usf.mFileId, usf.mUserId, mPersistInfoProvider);
- }
- Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
- }
- });
+ for (int i = removeTargets.size() - 1; i >= 0; --i) {
+ final UserSavedFile usf = removeTargets.get(i);
+ mPersister.removeSnapshot(usf.mFileId, usf.mUserId);
}
}
diff --git a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
index 4681396..688a3b5 100644
--- a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
+++ b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
@@ -719,14 +719,6 @@
&& !state.realCallerExplicitOptOut();
if (callerCanAllow) {
// Allowed before V by creator
- if (state.mBalAllowedByPiCreatorWithHardening.allowsBackgroundActivityStarts()) {
- // Will be allowed even with BAL hardening.
- if (DEBUG_ACTIVITY_STARTS) {
- Slog.d(TAG, "Activity start allowed by caller. "
- + state.dump());
- }
- return allowBasedOnCaller(state);
- }
if (state.mBalAllowedByPiCreator.allowsBackgroundActivityStarts()) {
Slog.wtf(TAG, "With Android 15 BAL hardening this activity start may be blocked"
+ " if the PI creator upgrades target_sdk to 35+! "
@@ -997,7 +989,7 @@
BalVerdict balAllowedForUid = proc.areBackgroundActivityStartsAllowed(
state.mAppSwitchState);
if (balAllowedForUid.allows()) {
- return balAllowedForCaller.withProcessInfo("process", proc);
+ return balAllowedForUid.withProcessInfo("process", proc);
}
}
}
diff --git a/services/core/java/com/android/server/wm/DeferredDisplayUpdater.java b/services/core/java/com/android/server/wm/DeferredDisplayUpdater.java
index 0f9e5b0..7052982 100644
--- a/services/core/java/com/android/server/wm/DeferredDisplayUpdater.java
+++ b/services/core/java/com/android/server/wm/DeferredDisplayUpdater.java
@@ -183,9 +183,6 @@
getCurrentDisplayChange(fromRotation, startBounds);
mDisplayContent.mTransitionController.requestStartTransition(transition,
/* startTask= */ null, /* remoteTransition= */ null, displayChange);
- mDisplayContent.mTransitionController.setDisplaySyncMethod(displayChange,
- mDisplayContent);
- transition.setAllReady();
}
});
}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index e7ecf52..82dbf8d 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -160,6 +160,7 @@
import static com.android.server.wm.utils.DisplayInfoOverrides.copyDisplayInfoFields;
import static com.android.server.wm.utils.RegionUtils.forEachRectReverse;
import static com.android.server.wm.utils.RegionUtils.rectListToRegion;
+import static com.android.window.flags.Flags.deferDisplayUpdates;
import static com.android.window.flags.Flags.explicitRefreshRateHints;
import android.annotation.IntDef;
@@ -174,7 +175,6 @@
import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
-import android.graphics.Bitmap;
import android.graphics.ColorSpace;
import android.graphics.Insets;
import android.graphics.Matrix;
@@ -246,7 +246,6 @@
import android.window.DisplayWindowPolicyController;
import android.window.IDisplayAreaOrganizer;
import android.window.ScreenCapture;
-import android.window.ScreenCapture.SynchronousScreenCaptureListener;
import android.window.SystemPerformanceHinter;
import android.window.TransitionRequestInfo;
@@ -276,7 +275,6 @@
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Predicate;
-import static com.android.window.flags.Flags.deferDisplayUpdates;
/**
* Utility class for keeping track of the WindowStates and other pertinent contents of a
@@ -1636,12 +1634,19 @@
if (configChanged) {
mWaitingForConfig = true;
if (mTransitionController.isShellTransitionsEnabled()) {
- final TransitionRequestInfo.DisplayChange change =
- mTransitionController.isCollecting()
+ final Rect startBounds = currentDisplayConfig.windowConfiguration.getBounds();
+ final Rect endBounds = mTmpConfiguration.windowConfiguration.getBounds();
+ final Transition transition = mTransitionController.getCollectingTransition();
+ final TransitionRequestInfo.DisplayChange change = transition != null
? null : new TransitionRequestInfo.DisplayChange(mDisplayId);
if (change != null) {
- change.setStartAbsBounds(currentDisplayConfig.windowConfiguration.getBounds());
- change.setEndAbsBounds(mTmpConfiguration.windowConfiguration.getBounds());
+ change.setStartAbsBounds(startBounds);
+ change.setEndAbsBounds(endBounds);
+ } else {
+ transition.setKnownConfigChanges(this, changes);
+ // A collecting transition is existed. The sync method must be set before
+ // collecting this display, so WindowState#prepareSync can use the sync method.
+ mTransitionController.setDisplaySyncMethod(startBounds, endBounds, this);
}
requestChangeTransitionIfNeeded(changes, change);
} else if (mLastHasContent) {
@@ -5207,10 +5212,9 @@
}
/**
- * Takes a snapshot of the display. In landscape mode this grabs the whole screen.
- * In portrait mode, it grabs the full screenshot.
+ * Creates a LayerCaptureArgs object to represent the entire DisplayContent
*/
- Bitmap screenshotDisplayLocked() {
+ ScreenCapture.LayerCaptureArgs getLayerCaptureArgs() {
if (!mWmService.mPolicy.isScreenOn()) {
if (DEBUG_SCREENSHOT) {
Slog.i(TAG_WM, "Attempted to take screenshot while display was off.");
@@ -5218,24 +5222,10 @@
return null;
}
- SynchronousScreenCaptureListener syncScreenCapture =
- ScreenCapture.createSyncCaptureListener();
-
getBounds(mTmpRect);
mTmpRect.offsetTo(0, 0);
- ScreenCapture.LayerCaptureArgs args =
- new ScreenCapture.LayerCaptureArgs.Builder(getSurfaceControl())
- .setSourceCrop(mTmpRect).build();
-
- ScreenCapture.captureLayers(args, syncScreenCapture);
-
- final ScreenCapture.ScreenshotHardwareBuffer screenshotBuffer =
- syncScreenCapture.getBuffer();
- final Bitmap bitmap = screenshotBuffer == null ? null : screenshotBuffer.asBitmap();
- if (bitmap == null) {
- Slog.w(TAG_WM, "Failed to take screenshot");
- }
- return bitmap;
+ return new ScreenCapture.LayerCaptureArgs.Builder(getSurfaceControl())
+ .setSourceCrop(mTmpRect).build();
}
@Override
diff --git a/services/core/java/com/android/server/wm/ScreenRecordingCallbackController.java b/services/core/java/com/android/server/wm/ScreenRecordingCallbackController.java
index 5f488b7..bdb4588 100644
--- a/services/core/java/com/android/server/wm/ScreenRecordingCallbackController.java
+++ b/services/core/java/com/android/server/wm/ScreenRecordingCallbackController.java
@@ -97,7 +97,7 @@
mRecordedWC = (WindowContainer) mWms.mRoot.getDefaultDisplay();
} else {
mRecordedWC = mWms.mRoot.getActivity(activity -> activity.mLaunchCookie
- == mediaProjectionInfo.getLaunchCookie()).getTask();
+ == mediaProjectionInfo.getLaunchCookie().binder).getTask();
}
}
diff --git a/services/core/java/com/android/server/wm/SnapshotController.java b/services/core/java/com/android/server/wm/SnapshotController.java
index 3014f97..cb388ef 100644
--- a/services/core/java/com/android/server/wm/SnapshotController.java
+++ b/services/core/java/com/android/server/wm/SnapshotController.java
@@ -211,5 +211,6 @@
void dump(PrintWriter pw, String prefix) {
mTaskSnapshotController.dump(pw, prefix);
mActivitySnapshotController.dump(pw, prefix);
+ mSnapshotPersistQueue.dump(pw, prefix);
}
}
diff --git a/services/core/java/com/android/server/wm/SnapshotPersistQueue.java b/services/core/java/com/android/server/wm/SnapshotPersistQueue.java
index e4379b5..3578971 100644
--- a/services/core/java/com/android/server/wm/SnapshotPersistQueue.java
+++ b/services/core/java/com/android/server/wm/SnapshotPersistQueue.java
@@ -41,6 +41,7 @@
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
+import java.io.PrintWriter;
import java.util.ArrayDeque;
/**
@@ -155,7 +156,9 @@
void deleteSnapshot(int index, int userId, PersistInfoProvider provider) {
final File protoFile = provider.getProtoFile(index, userId);
final File bitmapLowResFile = provider.getLowResolutionBitmapFile(index, userId);
- protoFile.delete();
+ if (protoFile.exists()) {
+ protoFile.delete();
+ }
if (bitmapLowResFile.exists()) {
bitmapLowResFile.delete();
}
@@ -177,7 +180,7 @@
} else {
next = mWriteQueue.poll();
if (next != null) {
- if (next.isReady()) {
+ if (next.isReady(mUserManagerInternal)) {
isReadyToWrite = true;
next.onDequeuedLocked();
} else {
@@ -210,14 +213,16 @@
abstract static class WriteQueueItem {
protected final PersistInfoProvider mPersistInfoProvider;
- WriteQueueItem(@NonNull PersistInfoProvider persistInfoProvider) {
+ protected final int mUserId;
+ WriteQueueItem(@NonNull PersistInfoProvider persistInfoProvider, int userId) {
mPersistInfoProvider = persistInfoProvider;
+ mUserId = userId;
}
/**
* @return {@code true} if item is ready to have {@link WriteQueueItem#write} called
*/
- boolean isReady() {
- return true;
+ boolean isReady(UserManagerInternal userManager) {
+ return userManager.isUserUnlocked(mUserId);
}
abstract void write();
@@ -242,14 +247,12 @@
class StoreWriteQueueItem extends WriteQueueItem {
private final int mId;
- private final int mUserId;
private final TaskSnapshot mSnapshot;
StoreWriteQueueItem(int id, int userId, TaskSnapshot snapshot,
PersistInfoProvider provider) {
- super(provider);
+ super(provider, userId);
mId = id;
- mUserId = userId;
mSnapshot = snapshot;
}
@@ -268,11 +271,6 @@
}
@Override
- boolean isReady() {
- return mUserManagerInternal.isUserUnlocked(mUserId);
- }
-
- @Override
void write() {
if (Trace.isTagEnabled(TRACE_TAG_WINDOW_MANAGER)) {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "StoreWriteQueueItem#" + mId);
@@ -391,6 +389,11 @@
return mId == other.mId && mUserId == other.mUserId
&& mPersistInfoProvider == other.mPersistInfoProvider;
}
+
+ @Override
+ public String toString() {
+ return "StoreWriteQueueItem{ID=" + mId + ", UserId=" + mUserId + "}";
+ }
}
DeleteWriteQueueItem createDeleteWriteQueueItem(int id, int userId,
@@ -400,12 +403,10 @@
private class DeleteWriteQueueItem extends WriteQueueItem {
private final int mId;
- private final int mUserId;
DeleteWriteQueueItem(int id, int userId, PersistInfoProvider provider) {
- super(provider);
+ super(provider, userId);
mId = id;
- mUserId = userId;
}
@Override
@@ -414,5 +415,24 @@
deleteSnapshot(mId, mUserId, mPersistInfoProvider);
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
+
+ @Override
+ public String toString() {
+ return "DeleteWriteQueueItem{ID=" + mId + ", UserId=" + mUserId + "}";
+ }
+ }
+
+ void dump(PrintWriter pw, String prefix) {
+ final WriteQueueItem[] items;
+ synchronized (mLock) {
+ items = mWriteQueue.toArray(new WriteQueueItem[0]);
+ }
+ if (items.length == 0) {
+ return;
+ }
+ pw.println(prefix + "PersistQueue contains:");
+ for (int i = items.length - 1; i >= 0; --i) {
+ pw.println(prefix + " " + items[i] + "");
+ }
}
}
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index b2b547e..11e7bb0 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -16,6 +16,7 @@
package com.android.server.wm;
+import static android.Manifest.permission.EMBED_ANY_APP_IN_UNTRUSTED_MODE;
import static android.Manifest.permission.MANAGE_ACTIVITY_TASKS;
import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
@@ -725,6 +726,9 @@
// TaskFragment to have bounds outside of the parent bounds.
return false;
}
+ if (hasEmbedAnyAppInUntrustedModePermission(mTaskFragmentOrganizerUid)) {
+ return true;
+ }
return (a.info.flags & FLAG_ALLOW_UNTRUSTED_ACTIVITY_EMBEDDING)
== FLAG_ALLOW_UNTRUSTED_ACTIVITY_EMBEDDING;
}
@@ -796,6 +800,15 @@
}
/**
+ * Checks if a particular app uid has the {@link EMBED_ANY_APP_IN_UNTRUSTED_MODE} permission.
+ */
+ private static boolean hasEmbedAnyAppInUntrustedModePermission(int uid) {
+ return Flags.untrustedEmbeddingAnyAppPermission()
+ && checkPermission(EMBED_ANY_APP_IN_UNTRUSTED_MODE,
+ PermissionChecker.PID_UNKNOWN, uid) == PackageManager.PERMISSION_GRANTED;
+ }
+
+ /**
* Checks if all activities in the task fragment are embedded as fully trusted.
* @see #isFullyTrustedEmbedding(ActivityRecord, int)
* @param uid uid of the TaskFragment organizer.
diff --git a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
index 4e7a9bd..f4e9957 100644
--- a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
+++ b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
@@ -303,8 +303,15 @@
} else {
if (DEBUG) appendLog("non-freeform-task-display-area");
}
+ final boolean isUpdatingExistingTaskWindowingMode = task != null
+ && task.getRequestedOverrideWindowingMode() != WINDOWING_MODE_UNDEFINED
+ && launchMode != task.getRequestedOverrideWindowingMode();
+ if (DEBUG && isUpdatingExistingTaskWindowingMode) {
+ appendLog("updating-existing-task-windowing-mode");
+ }
// If launch mode matches display windowing mode, let it inherit from display.
outParams.mWindowingMode = launchMode == suggestedDisplayArea.getWindowingMode()
+ && !isUpdatingExistingTaskWindowingMode
? WINDOWING_MODE_UNDEFINED : launchMode;
if (phase == PHASE_WINDOWING_MODE) {
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotPersister.java b/services/core/java/com/android/server/wm/TaskSnapshotPersister.java
index 233daad..87be74a 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotPersister.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotPersister.java
@@ -19,11 +19,13 @@
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
import android.os.Trace;
+import android.os.UserHandle;
import android.util.ArraySet;
import android.window.TaskSnapshot;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.pm.UserManagerInternal;
import java.io.File;
import java.util.Arrays;
@@ -84,6 +86,9 @@
* model.
*/
void removeObsoleteFiles(ArraySet<Integer> persistentTaskIds, int[] runningUserIds) {
+ if (runningUserIds.length == 0) {
+ return;
+ }
synchronized (mLock) {
mPersistedTaskIdsSinceLastRemoveObsolete.clear();
mSnapshotPersistQueue.sendToQueueLocked(new RemoveObsoleteFilesQueueItem(
@@ -99,12 +104,22 @@
@VisibleForTesting
RemoveObsoleteFilesQueueItem(ArraySet<Integer> persistentTaskIds,
int[] runningUserIds, PersistInfoProvider provider) {
- super(provider);
+ super(provider, runningUserIds.length > 0 ? runningUserIds[0] : UserHandle.USER_SYSTEM);
mPersistentTaskIds = new ArraySet<>(persistentTaskIds);
mRunningUserIds = Arrays.copyOf(runningUserIds, runningUserIds.length);
}
@Override
+ boolean isReady(UserManagerInternal userManagerInternal) {
+ for (int i = mRunningUserIds.length - 1; i >= 0; --i) {
+ if (!userManagerInternal.isUserUnlocked(mRunningUserIds[i])) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
void write() {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "RemoveObsoleteFilesQueueItem");
final ArraySet<Integer> newPersistedTaskIds;
diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java
index d7b4a39..25b5630f 100644
--- a/services/core/java/com/android/server/wm/TransitionController.java
+++ b/services/core/java/com/android/server/wm/TransitionController.java
@@ -640,11 +640,16 @@
}
/** Sets the sync method for the display change. */
- void setDisplaySyncMethod(@NonNull TransitionRequestInfo.DisplayChange displayChange,
+ private void setDisplaySyncMethod(@NonNull TransitionRequestInfo.DisplayChange displayChange,
@NonNull DisplayContent displayContent) {
final Rect startBounds = displayChange.getStartAbsBounds();
final Rect endBounds = displayChange.getEndAbsBounds();
if (startBounds == null || endBounds == null) return;
+ setDisplaySyncMethod(startBounds, endBounds, displayContent);
+ }
+
+ void setDisplaySyncMethod(@NonNull Rect startBounds, @NonNull Rect endBounds,
+ @NonNull DisplayContent displayContent) {
final int startWidth = startBounds.width();
final int startHeight = startBounds.height();
final int endWidth = endBounds.width();
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index 399815b..6949a87 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -279,13 +279,14 @@
return null;
}
Point largestDisplaySize = new Point();
+ float largestWidth = 0;
List<DisplayInfo> possibleDisplayInfo =
mService.getPossibleDisplayInfoLocked(DEFAULT_DISPLAY);
for (int i = 0; i < possibleDisplayInfo.size(); i++) {
DisplayInfo displayInfo = possibleDisplayInfo.get(i);
- if (displayInfo.type == Display.TYPE_INTERNAL
- && Math.max(displayInfo.logicalWidth, displayInfo.logicalHeight)
- > Math.max(largestDisplaySize.x, largestDisplaySize.y)) {
+ float width = (float) displayInfo.logicalWidth / displayInfo.physicalXDpi;
+ if (displayInfo.type == Display.TYPE_INTERNAL && width > largestWidth) {
+ largestWidth = width;
largestDisplaySize.set(displayInfo.logicalWidth,
displayInfo.logicalHeight);
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 9650b8bc..426694d 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -4087,7 +4087,7 @@
throw new SecurityException("Requires READ_FRAME_BUFFER permission");
}
- final Bitmap bm;
+ ScreenCapture.LayerCaptureArgs captureArgs;
synchronized (mGlobalLock) {
final DisplayContent displayContent = mRoot.getDisplayContent(DEFAULT_DISPLAY);
if (displayContent == null) {
@@ -4095,12 +4095,30 @@
Slog.i(TAG_WM, "Screenshot returning null. No Display for displayId="
+ DEFAULT_DISPLAY);
}
- bm = null;
+ captureArgs = null;
} else {
- bm = displayContent.screenshotDisplayLocked();
+ captureArgs = displayContent.getLayerCaptureArgs();
}
}
+ final Bitmap bm;
+ if (captureArgs != null) {
+ ScreenCapture.SynchronousScreenCaptureListener syncScreenCapture =
+ ScreenCapture.createSyncCaptureListener();
+
+ ScreenCapture.captureLayers(captureArgs, syncScreenCapture);
+
+ final ScreenCapture.ScreenshotHardwareBuffer screenshotBuffer =
+ syncScreenCapture.getBuffer();
+ bm = screenshotBuffer == null ? null : screenshotBuffer.asBitmap();
+ } else {
+ bm = null;
+ }
+
+ if (bm == null) {
+ Slog.w(TAG_WM, "Failed to take screenshot");
+ }
+
FgThread.getHandler().post(() -> {
try {
receiver.onHandleAssistScreenshot(bm);
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index 4ba52e4..3f889c0 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -1471,7 +1471,12 @@
final int index = task.mChildren.indexOf(topTaskFragment);
task.mChildren.remove(taskFragment);
task.mChildren.add(index, taskFragment);
- effects |= TRANSACT_EFFECTS_LIFECYCLE;
+ if (taskFragment.hasChild()) {
+ effects |= TRANSACT_EFFECTS_LIFECYCLE;
+ } else {
+ // Ensure that the child layers are updated if the TaskFragment is empty
+ task.assignChildLayers();
+ }
}
}
break;
@@ -1486,7 +1491,12 @@
if (task != null) {
task.mChildren.remove(taskFragment);
task.mChildren.add(0, taskFragment);
- effects |= TRANSACT_EFFECTS_LIFECYCLE;
+ if (taskFragment.hasChild()) {
+ effects |= TRANSACT_EFFECTS_LIFECYCLE;
+ } else {
+ // Ensure that the child layers are updated if the TaskFragment is empty.
+ task.assignChildLayers();
+ }
}
break;
}
@@ -1495,7 +1505,12 @@
if (task != null) {
task.mChildren.remove(taskFragment);
task.mChildren.add(taskFragment);
- effects |= TRANSACT_EFFECTS_LIFECYCLE;
+ if (taskFragment.hasChild()) {
+ effects |= TRANSACT_EFFECTS_LIFECYCLE;
+ } else {
+ // Ensure that the child layers are updated if the TaskFragment is empty.
+ task.assignChildLayers();
+ }
}
break;
}
diff --git a/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp b/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp
index 7b08413..4403bce 100644
--- a/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp
+++ b/services/core/jni/com_android_server_am_CachedAppOptimizer.cpp
@@ -571,8 +571,8 @@
}
static jboolean com_android_server_am_CachedAppOptimizer_isFreezerProfileValid(JNIEnv* env) {
- int uid = getuid();
- int pid = getpid();
+ uid_t uid = getuid();
+ pid_t pid = getpid();
return isProfileValidForProcess("Frozen", uid, pid) &&
isProfileValidForProcess("Unfrozen", uid, pid);
diff --git a/services/credentials/java/com/android/server/credentials/ClearRequestSession.java b/services/credentials/java/com/android/server/credentials/ClearRequestSession.java
index db985fd..b1349ea 100644
--- a/services/credentials/java/com/android/server/credentials/ClearRequestSession.java
+++ b/services/credentials/java/com/android/server/credentials/ClearRequestSession.java
@@ -23,8 +23,8 @@
import android.credentials.ClearCredentialStateRequest;
import android.credentials.CredentialProviderInfo;
import android.credentials.IClearCredentialStateCallback;
-import android.credentials.ui.ProviderData;
-import android.credentials.ui.RequestInfo;
+import android.credentials.selection.ProviderData;
+import android.credentials.selection.RequestInfo;
import android.os.CancellationSignal;
import android.os.RemoteException;
import android.service.credentials.CallingAppInfo;
diff --git a/services/credentials/java/com/android/server/credentials/CreateRequestSession.java b/services/credentials/java/com/android/server/credentials/CreateRequestSession.java
index b24accb..3dcf42d 100644
--- a/services/credentials/java/com/android/server/credentials/CreateRequestSession.java
+++ b/services/credentials/java/com/android/server/credentials/CreateRequestSession.java
@@ -27,8 +27,8 @@
import android.credentials.CredentialManager;
import android.credentials.CredentialProviderInfo;
import android.credentials.ICreateCredentialCallback;
-import android.credentials.ui.ProviderData;
-import android.credentials.ui.RequestInfo;
+import android.credentials.selection.ProviderData;
+import android.credentials.selection.RequestInfo;
import android.os.CancellationSignal;
import android.os.RemoteException;
import android.service.credentials.CallingAppInfo;
diff --git a/services/credentials/java/com/android/server/credentials/CredentialManagerService.java b/services/credentials/java/com/android/server/credentials/CredentialManagerService.java
index 667e086..281fb1c 100644
--- a/services/credentials/java/com/android/server/credentials/CredentialManagerService.java
+++ b/services/credentials/java/com/android/server/credentials/CredentialManagerService.java
@@ -27,6 +27,7 @@
import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.content.ComponentName;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
@@ -201,7 +202,7 @@
@SuppressWarnings("GuardedBy") // ErrorProne requires service.mLock which is the same
// this.mLock
protected void handlePackageRemovedMultiModeLocked(String packageName, int userId) {
- updateProvidersWhenPackageRemoved(mContext, packageName);
+ updateProvidersWhenPackageRemoved(new SettingsWrapper(mContext), packageName);
List<CredentialManagerServiceImpl> services = peekServiceListForUserLocked(userId);
if (services == null) {
@@ -1134,13 +1135,14 @@
}
/** Updates the list of providers when an app is uninstalled. */
- public static void updateProvidersWhenPackageRemoved(Context context, String packageName) {
+ public static void updateProvidersWhenPackageRemoved(
+ SettingsWrapper settingsWrapper, String packageName) {
+ Slog.i(TAG, "updateProvidersWhenPackageRemoved");
+
// Get the current providers.
String rawProviders =
- Settings.Secure.getStringForUser(
- context.getContentResolver(),
- Settings.Secure.CREDENTIAL_SERVICE_PRIMARY,
- UserHandle.myUserId());
+ settingsWrapper.getStringForUser(
+ Settings.Secure.CREDENTIAL_SERVICE_PRIMARY, UserHandle.myUserId());
if (rawProviders == null) {
Slog.w(TAG, "settings key is null");
return;
@@ -1148,44 +1150,44 @@
// Remove any providers from the primary setting that contain the package name
// being removed.
- Set<String> primaryProviders =
- getStoredProviders(rawProviders, packageName);
- if (!Settings.Secure.putString(
- context.getContentResolver(),
+ Set<String> primaryProviders = getStoredProviders(rawProviders, packageName);
+ if (!settingsWrapper.putStringForUser(
Settings.Secure.CREDENTIAL_SERVICE_PRIMARY,
- String.join(":", primaryProviders))) {
- Slog.w(TAG, "Failed to remove primary package: " + packageName);
+ String.join(":", primaryProviders),
+ UserHandle.myUserId(),
+ /* overrideableByRestore= */ true)) {
+ Slog.e(TAG, "Failed to remove primary package: " + packageName);
return;
}
// Read the autofill provider so we don't accidentally erase it.
String autofillProvider =
- Settings.Secure.getStringForUser(
- context.getContentResolver(),
- Settings.Secure.AUTOFILL_SERVICE,
- UserHandle.myUserId());
+ settingsWrapper.getStringForUser(
+ Settings.Secure.AUTOFILL_SERVICE, UserHandle.myUserId());
// If there is an autofill provider and it is the placeholder indicating
// that the currently selected primary provider does not support autofill
// then we should wipe the setting to keep it in sync.
if (autofillProvider != null && primaryProviders.isEmpty()) {
if (autofillProvider.equals(AUTOFILL_PLACEHOLDER_VALUE)) {
- if (!Settings.Secure.putString(
- context.getContentResolver(),
+ if (!settingsWrapper.putStringForUser(
Settings.Secure.AUTOFILL_SERVICE,
- "")) {
- Slog.w(TAG, "Failed to remove autofill package: " + packageName);
+ "",
+ UserHandle.myUserId(),
+ /* overrideableByRestore= */ true)) {
+ Slog.e(TAG, "Failed to remove autofill package: " + packageName);
}
} else {
// If the existing autofill provider is from the app being removed
// then erase the autofill service setting.
ComponentName cn = ComponentName.unflattenFromString(autofillProvider);
if (cn != null && cn.getPackageName().equals(packageName)) {
- if (!Settings.Secure.putString(
- context.getContentResolver(),
+ if (!settingsWrapper.putStringForUser(
Settings.Secure.AUTOFILL_SERVICE,
- "")) {
- Slog.w(TAG, "Failed to remove autofill package: " + packageName);
+ "",
+ UserHandle.myUserId(),
+ /* overrideableByRestore= */ true)) {
+ Slog.e(TAG, "Failed to remove autofill package: " + packageName);
}
}
}
@@ -1193,19 +1195,17 @@
// Read the credential providers to remove any reference of the removed app.
String rawCredentialProviders =
- Settings.Secure.getStringForUser(
- context.getContentResolver(),
- Settings.Secure.CREDENTIAL_SERVICE,
- UserHandle.myUserId());
+ settingsWrapper.getStringForUser(
+ Settings.Secure.CREDENTIAL_SERVICE, UserHandle.myUserId());
// Remove any providers that belong to the removed app.
- Set<String> credentialProviders =
- getStoredProviders(rawCredentialProviders, packageName);
- if (!Settings.Secure.putString(
- context.getContentResolver(),
+ Set<String> credentialProviders = getStoredProviders(rawCredentialProviders, packageName);
+ if (!settingsWrapper.putStringForUser(
Settings.Secure.CREDENTIAL_SERVICE,
- String.join(":", credentialProviders))) {
- Slog.w(TAG, "Failed to remove secondary package: " + packageName);
+ String.join(":", credentialProviders),
+ UserHandle.myUserId(),
+ /* overrideableByRestore= */ true)) {
+ Slog.e(TAG, "Failed to remove secondary package: " + packageName);
}
}
@@ -1232,4 +1232,38 @@
return providers;
}
+
+ /** A wrapper class that can be used by tests for intercepting reads/writes. */
+ public static class SettingsWrapper {
+ private final Context mContext;
+
+ public SettingsWrapper(@NonNull Context context) {
+ this.mContext = context;
+ }
+
+ ContentResolver getContentResolver() {
+ return mContext.getContentResolver();
+ }
+
+ /** Retrieves the string value of a system setting */
+ public String getStringForUser(String name, int userHandle) {
+ return Settings.Secure.getStringForUser(getContentResolver(), name, userHandle);
+ }
+
+ /** Updates the string value of a system setting */
+ public boolean putStringForUser(
+ String name,
+ String value,
+ int userHandle,
+ boolean overrideableByRestore) {
+ return Settings.Secure.putStringForUser(
+ getContentResolver(),
+ name,
+ value,
+ null,
+ false,
+ userHandle,
+ overrideableByRestore);
+ }
+ }
}
diff --git a/services/credentials/java/com/android/server/credentials/CredentialManagerUi.java b/services/credentials/java/com/android/server/credentials/CredentialManagerUi.java
index f092dcc..4203576 100644
--- a/services/credentials/java/com/android/server/credentials/CredentialManagerUi.java
+++ b/services/credentials/java/com/android/server/credentials/CredentialManagerUi.java
@@ -22,11 +22,11 @@
import android.content.Intent;
import android.credentials.CredentialManager;
import android.credentials.CredentialProviderInfo;
-import android.credentials.ui.DisabledProviderData;
-import android.credentials.ui.IntentFactory;
-import android.credentials.ui.ProviderData;
-import android.credentials.ui.RequestInfo;
-import android.credentials.ui.UserSelectionDialogResult;
+import android.credentials.selection.DisabledProviderData;
+import android.credentials.selection.IntentFactory;
+import android.credentials.selection.ProviderData;
+import android.credentials.selection.RequestInfo;
+import android.credentials.selection.UserSelectionDialogResult;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
diff --git a/services/credentials/java/com/android/server/credentials/GetCandidateRequestSession.java b/services/credentials/java/com/android/server/credentials/GetCandidateRequestSession.java
index 25281ba..7e709fe 100644
--- a/services/credentials/java/com/android/server/credentials/GetCandidateRequestSession.java
+++ b/services/credentials/java/com/android/server/credentials/GetCandidateRequestSession.java
@@ -26,9 +26,9 @@
import android.credentials.GetCredentialRequest;
import android.credentials.GetCredentialResponse;
import android.credentials.IGetCandidateCredentialsCallback;
-import android.credentials.ui.GetCredentialProviderData;
-import android.credentials.ui.ProviderData;
-import android.credentials.ui.RequestInfo;
+import android.credentials.selection.GetCredentialProviderData;
+import android.credentials.selection.ProviderData;
+import android.credentials.selection.RequestInfo;
import android.os.CancellationSignal;
import android.os.IBinder;
import android.os.RemoteException;
diff --git a/services/credentials/java/com/android/server/credentials/GetRequestSession.java b/services/credentials/java/com/android/server/credentials/GetRequestSession.java
index 49ea19a..b33f531 100644
--- a/services/credentials/java/com/android/server/credentials/GetRequestSession.java
+++ b/services/credentials/java/com/android/server/credentials/GetRequestSession.java
@@ -26,8 +26,8 @@
import android.credentials.GetCredentialRequest;
import android.credentials.GetCredentialResponse;
import android.credentials.IGetCredentialCallback;
-import android.credentials.ui.ProviderData;
-import android.credentials.ui.RequestInfo;
+import android.credentials.selection.ProviderData;
+import android.credentials.selection.RequestInfo;
import android.os.Binder;
import android.os.CancellationSignal;
import android.os.RemoteException;
diff --git a/services/credentials/java/com/android/server/credentials/PendingIntentResultHandler.java b/services/credentials/java/com/android/server/credentials/PendingIntentResultHandler.java
index efb394d..21ac9e4 100644
--- a/services/credentials/java/com/android/server/credentials/PendingIntentResultHandler.java
+++ b/services/credentials/java/com/android/server/credentials/PendingIntentResultHandler.java
@@ -22,7 +22,7 @@
import android.credentials.CreateCredentialResponse;
import android.credentials.GetCredentialException;
import android.credentials.GetCredentialResponse;
-import android.credentials.ui.ProviderPendingIntentResponse;
+import android.credentials.selection.ProviderPendingIntentResponse;
import android.service.credentials.BeginGetCredentialResponse;
import android.service.credentials.CredentialProviderService;
diff --git a/services/credentials/java/com/android/server/credentials/PrepareGetRequestSession.java b/services/credentials/java/com/android/server/credentials/PrepareGetRequestSession.java
index fbfc9ca..30af567 100644
--- a/services/credentials/java/com/android/server/credentials/PrepareGetRequestSession.java
+++ b/services/credentials/java/com/android/server/credentials/PrepareGetRequestSession.java
@@ -26,9 +26,9 @@
import android.credentials.IGetCredentialCallback;
import android.credentials.IPrepareGetCredentialCallback;
import android.credentials.PrepareGetCredentialResponseInternal;
-import android.credentials.ui.GetCredentialProviderData;
-import android.credentials.ui.ProviderData;
-import android.credentials.ui.RequestInfo;
+import android.credentials.selection.GetCredentialProviderData;
+import android.credentials.selection.ProviderData;
+import android.credentials.selection.RequestInfo;
import android.os.CancellationSignal;
import android.os.RemoteException;
import android.service.credentials.CallingAppInfo;
diff --git a/services/credentials/java/com/android/server/credentials/ProviderClearSession.java b/services/credentials/java/com/android/server/credentials/ProviderClearSession.java
index d4b8800..6a1b1db7 100644
--- a/services/credentials/java/com/android/server/credentials/ProviderClearSession.java
+++ b/services/credentials/java/com/android/server/credentials/ProviderClearSession.java
@@ -21,8 +21,8 @@
import android.content.Context;
import android.credentials.ClearCredentialStateException;
import android.credentials.CredentialProviderInfo;
-import android.credentials.ui.ProviderData;
-import android.credentials.ui.ProviderPendingIntentResponse;
+import android.credentials.selection.ProviderData;
+import android.credentials.selection.ProviderPendingIntentResponse;
import android.os.ICancellationSignal;
import android.service.credentials.CallingAppInfo;
import android.service.credentials.ClearCredentialStateRequest;
diff --git a/services/credentials/java/com/android/server/credentials/ProviderCreateSession.java b/services/credentials/java/com/android/server/credentials/ProviderCreateSession.java
index 6f79852..6361aeb 100644
--- a/services/credentials/java/com/android/server/credentials/ProviderCreateSession.java
+++ b/services/credentials/java/com/android/server/credentials/ProviderCreateSession.java
@@ -25,9 +25,9 @@
import android.credentials.CreateCredentialException;
import android.credentials.CreateCredentialResponse;
import android.credentials.CredentialProviderInfo;
-import android.credentials.ui.CreateCredentialProviderData;
-import android.credentials.ui.Entry;
-import android.credentials.ui.ProviderPendingIntentResponse;
+import android.credentials.selection.CreateCredentialProviderData;
+import android.credentials.selection.Entry;
+import android.credentials.selection.ProviderPendingIntentResponse;
import android.os.Bundle;
import android.os.ICancellationSignal;
import android.service.credentials.BeginCreateCredentialRequest;
diff --git a/services/credentials/java/com/android/server/credentials/ProviderGetSession.java b/services/credentials/java/com/android/server/credentials/ProviderGetSession.java
index 7bd1cc4..fcaef9f 100644
--- a/services/credentials/java/com/android/server/credentials/ProviderGetSession.java
+++ b/services/credentials/java/com/android/server/credentials/ProviderGetSession.java
@@ -26,10 +26,10 @@
import android.credentials.CredentialProviderInfo;
import android.credentials.GetCredentialException;
import android.credentials.GetCredentialResponse;
-import android.credentials.ui.AuthenticationEntry;
-import android.credentials.ui.Entry;
-import android.credentials.ui.GetCredentialProviderData;
-import android.credentials.ui.ProviderPendingIntentResponse;
+import android.credentials.selection.AuthenticationEntry;
+import android.credentials.selection.Entry;
+import android.credentials.selection.GetCredentialProviderData;
+import android.credentials.selection.ProviderPendingIntentResponse;
import android.os.ICancellationSignal;
import android.service.autofill.Flags;
import android.service.credentials.Action;
diff --git a/services/credentials/java/com/android/server/credentials/ProviderRegistryGetSession.java b/services/credentials/java/com/android/server/credentials/ProviderRegistryGetSession.java
index bafa4a5..f162916 100644
--- a/services/credentials/java/com/android/server/credentials/ProviderRegistryGetSession.java
+++ b/services/credentials/java/com/android/server/credentials/ProviderRegistryGetSession.java
@@ -25,10 +25,10 @@
import android.credentials.CredentialOption;
import android.credentials.GetCredentialException;
import android.credentials.GetCredentialResponse;
-import android.credentials.ui.Entry;
-import android.credentials.ui.GetCredentialProviderData;
-import android.credentials.ui.ProviderData;
-import android.credentials.ui.ProviderPendingIntentResponse;
+import android.credentials.selection.Entry;
+import android.credentials.selection.GetCredentialProviderData;
+import android.credentials.selection.ProviderData;
+import android.credentials.selection.ProviderPendingIntentResponse;
import android.os.ICancellationSignal;
import android.service.credentials.CallingAppInfo;
import android.service.credentials.CredentialEntry;
diff --git a/services/credentials/java/com/android/server/credentials/ProviderSession.java b/services/credentials/java/com/android/server/credentials/ProviderSession.java
index f2055d0..c16e232 100644
--- a/services/credentials/java/com/android/server/credentials/ProviderSession.java
+++ b/services/credentials/java/com/android/server/credentials/ProviderSession.java
@@ -25,8 +25,8 @@
import android.content.pm.PackageManager;
import android.credentials.Credential;
import android.credentials.CredentialProviderInfo;
-import android.credentials.ui.ProviderData;
-import android.credentials.ui.ProviderPendingIntentResponse;
+import android.credentials.selection.ProviderData;
+import android.credentials.selection.ProviderPendingIntentResponse;
import android.os.ICancellationSignal;
import android.os.RemoteException;
import android.util.Slog;
diff --git a/services/credentials/java/com/android/server/credentials/RequestSession.java b/services/credentials/java/com/android/server/credentials/RequestSession.java
index 67c52e6..bf7df86 100644
--- a/services/credentials/java/com/android/server/credentials/RequestSession.java
+++ b/services/credentials/java/com/android/server/credentials/RequestSession.java
@@ -24,8 +24,8 @@
import android.content.Intent;
import android.credentials.CredentialProviderInfo;
import android.credentials.flags.Flags;
-import android.credentials.ui.ProviderData;
-import android.credentials.ui.UserSelectionDialogResult;
+import android.credentials.selection.ProviderData;
+import android.credentials.selection.UserSelectionDialogResult;
import android.os.Binder;
import android.os.CancellationSignal;
import android.os.Handler;
diff --git a/services/credentials/java/com/android/server/credentials/metrics/ApiName.java b/services/credentials/java/com/android/server/credentials/metrics/ApiName.java
index d828349..23db11f 100644
--- a/services/credentials/java/com/android/server/credentials/metrics/ApiName.java
+++ b/services/credentials/java/com/android/server/credentials/metrics/ApiName.java
@@ -16,10 +16,10 @@
package com.android.server.credentials.metrics;
-import static android.credentials.ui.RequestInfo.TYPE_CREATE;
-import static android.credentials.ui.RequestInfo.TYPE_GET;
-import static android.credentials.ui.RequestInfo.TYPE_GET_VIA_REGISTRY;
-import static android.credentials.ui.RequestInfo.TYPE_UNDEFINED;
+import static android.credentials.selection.RequestInfo.TYPE_CREATE;
+import static android.credentials.selection.RequestInfo.TYPE_GET;
+import static android.credentials.selection.RequestInfo.TYPE_GET_VIA_REGISTRY;
+import static android.credentials.selection.RequestInfo.TYPE_UNDEFINED;
import static com.android.internal.util.FrameworkStatsLog.CREDENTIAL_MANAGER_INITIAL_PHASE_REPORTED__API_NAME__API_NAME_CLEAR_CREDENTIAL;
import static com.android.internal.util.FrameworkStatsLog.CREDENTIAL_MANAGER_INITIAL_PHASE_REPORTED__API_NAME__API_NAME_CREATE_CREDENTIAL;
@@ -32,7 +32,7 @@
import static com.android.internal.util.FrameworkStatsLog.CREDENTIAL_MANAGER_INITIAL_PHASE_REPORTED__API_NAME__API_NAME_UNKNOWN;
import static com.android.internal.util.FrameworkStatsLog.CREDENTIAL_MANAGER_INITIAL_PHASE_REPORTED__API_NAME__API_NAME_UNREGISTER_CREDENTIAL_DESCRIPTION;
-import android.credentials.ui.RequestInfo;
+import android.credentials.selection.RequestInfo;
import android.util.Slog;
import java.util.AbstractMap;
diff --git a/services/credentials/java/com/android/server/credentials/metrics/RequestSessionMetric.java b/services/credentials/java/com/android/server/credentials/metrics/RequestSessionMetric.java
index 83b57c4..8adcfbc 100644
--- a/services/credentials/java/com/android/server/credentials/metrics/RequestSessionMetric.java
+++ b/services/credentials/java/com/android/server/credentials/metrics/RequestSessionMetric.java
@@ -33,7 +33,7 @@
import android.content.ComponentName;
import android.credentials.CreateCredentialRequest;
import android.credentials.GetCredentialRequest;
-import android.credentials.ui.UserSelectionDialogResult;
+import android.credentials.selection.UserSelectionDialogResult;
import android.util.Slog;
import com.android.server.credentials.MetricUtilities;
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index f288103..519c9bb 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -71,6 +71,7 @@
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_SUPPORT_MESSAGE;
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_SYSTEM_DIALOGS;
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_SYSTEM_UPDATES;
+import static android.Manifest.permission.MANAGE_DEVICE_POLICY_THREAD_NETWORK;
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_TIME;
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_USB_DATA_SIGNALLING;
import static android.Manifest.permission.MANAGE_DEVICE_POLICY_USB_FILE_TRANSFER;
@@ -484,6 +485,7 @@
import com.android.modules.utils.TypedXmlPullParser;
import com.android.modules.utils.TypedXmlSerializer;
import com.android.net.module.util.ProxyUtils;
+import com.android.net.thread.flags.Flags;
import com.android.server.AlarmManagerInternal;
import com.android.server.LocalManagerRegistry;
import com.android.server.LocalServices;
@@ -13339,6 +13341,11 @@
UserManager.DISALLOW_SMS, new String[]{MANAGE_DEVICE_POLICY_SMS});
USER_RESTRICTION_PERMISSIONS.put(
UserManager.DISALLOW_SYSTEM_ERROR_DIALOGS, new String[]{MANAGE_DEVICE_POLICY_SYSTEM_DIALOGS});
+ if (Flags.threadUserRestrictionEnabled()) {
+ USER_RESTRICTION_PERMISSIONS.put(
+ UserManager.DISALLOW_THREAD_NETWORK,
+ new String[]{MANAGE_DEVICE_POLICY_THREAD_NETWORK});
+ }
USER_RESTRICTION_PERMISSIONS.put(
UserManager.DISALLOW_ULTRA_WIDEBAND_RADIO, new String[]{MANAGE_DEVICE_POLICY_NEARBY_COMMUNICATION});
USER_RESTRICTION_PERMISSIONS.put(
diff --git a/services/foldables/devicestateprovider/src/com/android/server/policy/FoldableDeviceStateProvider.java b/services/foldables/devicestateprovider/src/com/android/server/policy/FoldableDeviceStateProvider.java
index 4c487a7..ba72977 100644
--- a/services/foldables/devicestateprovider/src/com/android/server/policy/FoldableDeviceStateProvider.java
+++ b/services/foldables/devicestateprovider/src/com/android/server/policy/FoldableDeviceStateProvider.java
@@ -367,8 +367,11 @@
// TODO(b/312397262): consider virtual displays cases
synchronized (mLock) {
if (mIsDualDisplayBlockingEnabled
- && !mExternalDisplaysConnected.get(displayId, false)
- && mDisplayManager.getDisplay(displayId).getType() == TYPE_EXTERNAL) {
+ && !mExternalDisplaysConnected.get(displayId, false)) {
+ var display = mDisplayManager.getDisplay(displayId);
+ if (display == null || display.getType() != TYPE_EXTERNAL) {
+ return;
+ }
mExternalDisplaysConnected.put(displayId, true);
// Only update the supported state when going from 0 external display to 1
diff --git a/services/foldables/devicestateprovider/tests/src/com/android/server/policy/FoldableDeviceStateProviderTest.java b/services/foldables/devicestateprovider/tests/src/com/android/server/policy/FoldableDeviceStateProviderTest.java
index ddf4a08..04cebab 100644
--- a/services/foldables/devicestateprovider/tests/src/com/android/server/policy/FoldableDeviceStateProviderTest.java
+++ b/services/foldables/devicestateprovider/tests/src/com/android/server/policy/FoldableDeviceStateProviderTest.java
@@ -591,6 +591,20 @@
}
@Test
+ public void testOnDisplayAddedWithNullDisplayDoesNotThrowNPE() {
+ createProvider(
+ createConfig(
+ /* identifier= */ 1, /* name= */ "ONE",
+ /* flags= */0, (c) -> true,
+ FoldableDeviceStateProvider::hasNoConnectedExternalDisplay)
+ );
+
+ when(mDisplayManager.getDisplay(1)).thenReturn(null);
+ // This call should not throw NPE.
+ mProvider.onDisplayAdded(1);
+ }
+
+ @Test
public void hasNoConnectedDisplay_afterExternalDisplayAddedAndRemoved_returnsTrue() {
createProvider(
createConfig(
diff --git a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/ClientControllerTest.java b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/ClientControllerTest.java
index b9f1ea0..dc9631a 100644
--- a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/ClientControllerTest.java
+++ b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/ClientControllerTest.java
@@ -116,7 +116,7 @@
ANY_CALLER_PID);
verify(invoker.asBinder()).linkToDeath(any(IBinder.DeathRecipient.class), eq(0));
- assertThat(mController.mClients).containsEntry(invoker.asBinder(), added);
+ assertThat(mController.getClient(invoker.asBinder())).isSameInstanceAs(added);
}
}
@@ -133,7 +133,7 @@
var invoker = IInputMethodClientInvoker.create(mClient, mHandler);
added = mController.addClient(invoker, mConnection, ANY_DISPLAY_ID, ANY_CALLER_UID,
ANY_CALLER_PID);
- assertThat(mController.mClients).containsEntry(invoker.asBinder(), added);
+ assertThat(mController.getClient(invoker.asBinder())).isSameInstanceAs(added);
assertThat(mController.removeClient(mClient)).isTrue();
}
diff --git a/services/tests/PackageManagerServiceTests/server/Android.bp b/services/tests/PackageManagerServiceTests/server/Android.bp
index 3aca1ca..f8accc3 100644
--- a/services/tests/PackageManagerServiceTests/server/Android.bp
+++ b/services/tests/PackageManagerServiceTests/server/Android.bp
@@ -103,6 +103,7 @@
":PackageParserTestApp4",
":PackageParserTestApp5",
":PackageParserTestApp6",
+ ":PackageParserTestApp7",
],
resource_zips: [":PackageManagerServiceServerTests_apks_as_resources"],
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageParserTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageParserTest.java
index 71f5c75..a0e0e1e 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageParserTest.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageParserTest.java
@@ -15,6 +15,17 @@
*/
package com.android.server.pm;
+import static android.content.UriRelativeFilter.PATH;
+import static android.content.UriRelativeFilter.QUERY;
+import static android.content.UriRelativeFilter.FRAGMENT;
+import static android.content.UriRelativeFilterGroup.ACTION_ALLOW;
+import static android.content.UriRelativeFilterGroup.ACTION_BLOCK;
+import static android.os.PatternMatcher.PATTERN_ADVANCED_GLOB;
+import static android.os.PatternMatcher.PATTERN_LITERAL;
+import static android.os.PatternMatcher.PATTERN_PREFIX;
+import static android.os.PatternMatcher.PATTERN_SIMPLE_GLOB;
+import static android.os.PatternMatcher.PATTERN_SUFFIX;
+
import static com.android.internal.pm.permission.CompatibilityPermissionInfo.COMPAT_PERMS;
import static com.google.common.truth.Truth.assertThat;
@@ -36,11 +47,15 @@
import android.annotation.NonNull;
import android.content.Context;
+import android.content.IntentFilter;
+import android.content.UriRelativeFilter;
+import android.content.UriRelativeFilterGroup;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.ConfigurationInfo;
import android.content.pm.FeatureGroupInfo;
import android.content.pm.FeatureInfo;
+import android.content.pm.Flags;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager.Property;
import android.content.pm.ServiceInfo;
@@ -50,6 +65,9 @@
import android.os.Parcel;
import android.os.Parcelable;
import android.platform.test.annotations.Presubmit;
+import android.platform.test.annotations.RequiresFlagsEnabled;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.util.ArraySet;
import androidx.annotation.Nullable;
@@ -106,6 +124,7 @@
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
@@ -123,6 +142,9 @@
@Rule
public TemporaryFolder mTemporaryFolder = new TemporaryFolder();
+ @Rule
+ public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
+
private File mTmpDir;
private static final File FRAMEWORK = new File("/system/framework/framework-res.apk");
private static final String TEST_APP1_APK = "PackageParserTestApp1.apk";
@@ -131,6 +153,7 @@
private static final String TEST_APP4_APK = "PackageParserTestApp4.apk";
private static final String TEST_APP5_APK = "PackageParserTestApp5.apk";
private static final String TEST_APP6_APK = "PackageParserTestApp6.apk";
+ private static final String TEST_APP7_APK = "PackageParserTestApp7.apk";
private static final String PACKAGE_NAME = "com.android.servicestests.apps.packageparserapp";
@Before
@@ -375,6 +398,87 @@
assertNotEquals("$automotive", actualDisplayCategory);
}
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_RELATIVE_REFERENCE_INTENT_FILTERS)
+ public void testParseUriRelativeFilterGroups() throws Exception {
+ final File testFile = extractFile(TEST_APP7_APK);
+ try {
+ final ParsedPackage pkg = new TestPackageParser2().parsePackage(testFile, 0, false);
+ final List<ParsedActivity> activities = pkg.getActivities();
+ final List<ParsedIntentInfo> intents = activities.get(0).getIntents();
+ final IntentFilter intentFilter = intents.get(0).getIntentFilter();
+ assertEquals(7, intentFilter.countUriRelativeFilterGroups());
+
+ UriRelativeFilterGroup group = intentFilter.getUriRelativeFilterGroup(0);
+ Collection<UriRelativeFilter> filters = group.getUriRelativeFilters();
+ assertEquals(ACTION_BLOCK, group.getAction());
+ assertEquals(3, filters.size());
+ assertTrue(filters.contains(new UriRelativeFilter(PATH, PATTERN_PREFIX, "/gizmos")));
+ assertTrue(filters.contains(new UriRelativeFilter(QUERY, PATTERN_SIMPLE_GLOB,
+ ".*query=string.*")));
+ assertTrue(filters.contains(new UriRelativeFilter(FRAGMENT, PATTERN_LITERAL,
+ "fragment")));
+
+ group = intentFilter.getUriRelativeFilterGroup(1);
+ filters = group.getUriRelativeFilters();
+ assertEquals(ACTION_ALLOW, group.getAction());
+ assertEquals(2, filters.size());
+ assertTrue(filters.contains(new UriRelativeFilter(QUERY, PATTERN_LITERAL,
+ "query=string")));
+ assertTrue(filters.contains(new UriRelativeFilter(FRAGMENT, PATTERN_SUFFIX,
+ "fragment")));
+
+ group = intentFilter.getUriRelativeFilterGroup(2);
+ filters = group.getUriRelativeFilters();
+ assertEquals(ACTION_ALLOW, group.getAction());
+ assertTrue(filters.contains(new UriRelativeFilter(PATH, PATTERN_LITERAL, "/gizmos")));
+ assertTrue(filters.contains(new UriRelativeFilter(QUERY, PATTERN_LITERAL,
+ ".*query=string.*")));
+ assertTrue(filters.contains(new UriRelativeFilter(FRAGMENT, PATTERN_LITERAL,
+ "fragment")));
+
+ group = intentFilter.getUriRelativeFilterGroup(3);
+ filters = group.getUriRelativeFilters();
+ assertEquals(ACTION_ALLOW, group.getAction());
+ assertTrue(filters.contains(new UriRelativeFilter(PATH, PATTERN_PREFIX, "/gizmos")));
+ assertTrue(filters.contains(new UriRelativeFilter(QUERY, PATTERN_PREFIX,
+ ".*query=string.*")));
+ assertTrue(filters.contains(new UriRelativeFilter(FRAGMENT, PATTERN_PREFIX,
+ "fragment")));
+
+ group = intentFilter.getUriRelativeFilterGroup(4);
+ filters = group.getUriRelativeFilters();
+ assertEquals(ACTION_ALLOW, group.getAction());
+ assertTrue(filters.contains(new UriRelativeFilter(PATH, PATTERN_SIMPLE_GLOB,
+ "/gizmos")));
+ assertTrue(filters.contains(new UriRelativeFilter(QUERY, PATTERN_SIMPLE_GLOB,
+ ".*query=string.*")));
+ assertTrue(filters.contains(new UriRelativeFilter(FRAGMENT, PATTERN_SIMPLE_GLOB,
+ "fragment")));
+
+ group = intentFilter.getUriRelativeFilterGroup(5);
+ filters = group.getUriRelativeFilters();
+ assertEquals(ACTION_ALLOW, group.getAction());
+ assertTrue(filters.contains(new UriRelativeFilter(PATH, PATTERN_ADVANCED_GLOB,
+ "/gizmos")));
+ assertTrue(filters.contains(new UriRelativeFilter(QUERY, PATTERN_ADVANCED_GLOB,
+ ".*query=string.*")));
+ assertTrue(filters.contains(new UriRelativeFilter(FRAGMENT, PATTERN_ADVANCED_GLOB,
+ "fragment")));
+
+ group = intentFilter.getUriRelativeFilterGroup(6);
+ filters = group.getUriRelativeFilters();
+ assertEquals(ACTION_ALLOW, group.getAction());
+ assertTrue(filters.contains(new UriRelativeFilter(PATH, PATTERN_SUFFIX, "/gizmos")));
+ assertTrue(filters.contains(new UriRelativeFilter(QUERY, PATTERN_SUFFIX,
+ ".*query=string.*")));
+ assertTrue(filters.contains(new UriRelativeFilter(FRAGMENT, PATTERN_SUFFIX,
+ "fragment")));
+ } finally {
+ testFile.delete();
+ }
+ }
+
private static final int PROPERTY_TYPE_BOOLEAN = 1;
private static final int PROPERTY_TYPE_FLOAT = 2;
private static final int PROPERTY_TYPE_INTEGER = 3;
diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java
index 02e3ef4..75febd9 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java
@@ -61,6 +61,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.app.ActivityOptions.LaunchCookie;
import android.app.PropertyInvalidatedCache;
import android.companion.virtual.IVirtualDevice;
import android.companion.virtual.IVirtualDeviceManager;
@@ -1557,7 +1558,7 @@
when(mMockProjectionService
.setContentRecordingSession(any(ContentRecordingSession.class), eq(projection)))
.thenReturn(true);
- doReturn(mock(IBinder.class)).when(projection).getLaunchCookie();
+ doReturn(new LaunchCookie()).when(projection).getLaunchCookie();
doReturn(true).when(mMockProjectionService).isCurrentProjection(eq(projection));
final VirtualDisplayConfig.Builder builder = new VirtualDisplayConfig.Builder(
diff --git a/services/tests/displayservicetests/src/com/android/server/display/mode/DisplayModeDirectorTest.java b/services/tests/displayservicetests/src/com/android/server/display/mode/DisplayModeDirectorTest.java
index c556aca..64076e6 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/mode/DisplayModeDirectorTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/mode/DisplayModeDirectorTest.java
@@ -1727,6 +1727,7 @@
var desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID_2);
assertThat(desiredSpecs.primary.render.max).isEqualTo(expectedMaxRenderFrameRate);
+ assertThat(desiredSpecs.appRequest.render.max).isEqualTo(expectedMaxRenderFrameRate);
}
@Test
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/ServiceBindingOomAdjPolicyTest.java b/services/tests/mockingservicestests/src/com/android/server/am/ServiceBindingOomAdjPolicyTest.java
new file mode 100644
index 0000000..2f12a3b
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/am/ServiceBindingOomAdjPolicyTest.java
@@ -0,0 +1,677 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.am;
+
+import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_MICROPHONE;
+import static android.app.ActivityManager.PROCESS_CAPABILITY_NONE;
+import static android.app.ActivityManager.PROCESS_STATE_CACHED_EMPTY;
+import static android.app.ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
+import static android.app.ActivityManager.PROCESS_STATE_HOME;
+import static android.app.ActivityManager.PROCESS_STATE_LAST_ACTIVITY;
+import static android.app.ActivityManager.PROCESS_STATE_SERVICE;
+import static android.content.Context.BIND_AUTO_CREATE;
+import static android.content.Context.BIND_INCLUDE_CAPABILITIES;
+import static android.content.Context.BIND_WAIVE_PRIORITY;
+import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_SYSTEM_EXEMPTED;
+import static android.os.UserHandle.USER_SYSTEM;
+import static android.platform.test.flag.junit.SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT;
+
+import static com.android.server.am.ProcessList.HOME_APP_ADJ;
+import static com.android.server.am.ProcessList.PERCEPTIBLE_APP_ADJ;
+import static com.android.server.am.ProcessList.SERVICE_ADJ;
+import static com.android.server.am.ProcessList.CACHED_APP_MIN_ADJ;
+
+import static org.junit.Assert.assertNotEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.atLeastOnce;
+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.spy;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.app.IApplicationThread;
+import android.app.IServiceConnection;
+import android.app.usage.UsageStatsManagerInternal;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManagerInternal;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.IBinder;
+import android.platform.test.annotations.Presubmit;
+import android.platform.test.flag.junit.SetFlagsRule;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.server.DropBoxManagerInternal;
+import com.android.server.LocalServices;
+import com.android.server.am.ActivityManagerService.Injector;
+import com.android.server.am.ApplicationExitInfoTest.ServiceThreadRule;
+import com.android.server.appop.AppOpsService;
+import com.android.server.firewall.IntentFirewall;
+import com.android.server.wm.ActivityTaskManagerService;
+import com.android.server.wm.WindowProcessController;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Rule;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.verification.VerificationMode;
+
+import java.io.File;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.function.Consumer;
+
+/**
+ * Test class for the service timeout.
+ *
+ * Build/Install/Run:
+ * atest ServiceBindingOomAdjPolicyTest
+ */
+@Presubmit
+public final class ServiceBindingOomAdjPolicyTest {
+ private static final String TAG = ServiceBindingOomAdjPolicyTest.class.getSimpleName();
+
+ private static final String TEST_APP1_NAME = "com.example.foo";
+ private static final String TEST_SERVICE1_NAME = "com.example.foo.Foobar";
+ private static final int TEST_APP1_UID = 10123;
+ private static final int TEST_APP1_PID = 12345;
+
+ private static final String TEST_APP2_NAME = "com.example.bar";
+ private static final String TEST_SERVICE2_NAME = "com.example.bar.Buz";
+ private static final int TEST_APP2_UID = 10124;
+ private static final int TEST_APP2_PID = 12346;
+
+ @Rule
+ public final ServiceThreadRule mServiceThreadRule = new ServiceThreadRule();
+ @Rule
+ public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(DEVICE_DEFAULT);
+
+ private Context mContext;
+ private HandlerThread mHandlerThread;
+
+ @Mock
+ private AppOpsService mAppOpsService;
+ @Mock
+ private DropBoxManagerInternal mDropBoxManagerInt;
+ @Mock
+ private PackageManagerInternal mPackageManagerInt;
+ @Mock
+ private UsageStatsManagerInternal mUsageStatsManagerInt;
+ @Mock
+ private AppErrors mAppErrors;
+ @Mock
+ private IntentFirewall mIntentFirewall;
+
+ private ActivityManagerService mAms;
+ private ProcessList mProcessList;
+ private ActiveServices mActiveServices;
+
+ private int mCurrentCallingUid;
+ private int mCurrentCallingPid;
+
+ /** Run at the test class initialization */
+ @BeforeClass
+ public static void setUpOnce() {
+ System.setProperty("dexmaker.share_classloader", "true");
+ }
+
+ @SuppressWarnings("GuardedBy")
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+
+ mContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
+
+ mHandlerThread = new HandlerThread(TAG);
+ mHandlerThread.start();
+ final ProcessList realProcessList = new ProcessList();
+ mProcessList = spy(realProcessList);
+
+ LocalServices.removeServiceForTest(DropBoxManagerInternal.class);
+ LocalServices.addService(DropBoxManagerInternal.class, mDropBoxManagerInt);
+ LocalServices.removeServiceForTest(PackageManagerInternal.class);
+ LocalServices.addService(PackageManagerInternal.class, mPackageManagerInt);
+ doReturn(new ComponentName("", "")).when(mPackageManagerInt).getSystemUiServiceComponent();
+
+ final ActivityManagerService realAms = new ActivityManagerService(
+ new TestInjector(mContext), mServiceThreadRule.getThread());
+ final ActivityTaskManagerService realAtm = new ActivityTaskManagerService(mContext);
+ realAtm.initialize(null, null, mContext.getMainLooper());
+ realAms.mActivityTaskManager = spy(realAtm);
+ realAms.mAtmInternal = spy(realAms.mActivityTaskManager.getAtmInternal());
+ realAms.mOomAdjuster = spy(realAms.mOomAdjuster);
+ realAms.mOomAdjuster.mCachedAppOptimizer = spy(realAms.mOomAdjuster.mCachedAppOptimizer);
+ realAms.mPackageManagerInt = mPackageManagerInt;
+ realAms.mUsageStatsService = mUsageStatsManagerInt;
+ realAms.mAppProfiler = spy(realAms.mAppProfiler);
+ realAms.mProcessesReady = true;
+ mAms = spy(realAms);
+ realProcessList.mService = mAms;
+
+ doReturn(false).when(mPackageManagerInt).filterAppAccess(anyString(), anyInt(), anyInt());
+ doReturn(true).when(mIntentFirewall).checkService(any(), any(), anyInt(), anyInt(), any(),
+ any());
+ doReturn(false).when(mAms.mAtmInternal).hasSystemAlertWindowPermission(anyInt(), anyInt(),
+ any());
+ doReturn(true).when(mAms.mOomAdjuster.mCachedAppOptimizer).useFreezer();
+ doNothing().when(mAms.mOomAdjuster.mCachedAppOptimizer).freezeAppAsyncInternalLSP(
+ any(), anyLong(), anyBoolean());
+ doReturn(false).when(mAms.mAppProfiler).updateLowMemStateLSP(anyInt(), anyInt(),
+ anyInt(), anyLong());
+
+ mCurrentCallingUid = TEST_APP1_UID;
+ mCurrentCallingPid = TEST_APP1_PID;
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ LocalServices.removeServiceForTest(DropBoxManagerInternal.class);
+ LocalServices.removeServiceForTest(PackageManagerInternal.class);
+ mHandlerThread.quit();
+ }
+
+ @Test
+ public void testServiceSelfBindingOomAdj() throws Exception {
+ // Enable the flags.
+ mSetFlagsRule.enableFlags(Flags.FLAG_SERVICE_BINDING_OOM_ADJ_POLICY);
+
+ // Verify that there should be 0 oom adj updates.
+ performTestServiceSelfBindingOomAdj(never(), never());
+
+ // Disable the flags.
+ mSetFlagsRule.disableFlags(Flags.FLAG_SERVICE_BINDING_OOM_ADJ_POLICY);
+
+ // Verify that there should be at least 1 oom adj update.
+ performTestServiceSelfBindingOomAdj(atLeastOnce(), atLeastOnce());
+ }
+
+ @SuppressWarnings("GuardedBy")
+ private void performTestServiceSelfBindingOomAdj(VerificationMode bindMode,
+ VerificationMode unbindMode) throws Exception {
+ final ProcessRecord app = addProcessRecord(
+ TEST_APP1_PID, // pid
+ TEST_APP1_UID, // uid
+ PROCESS_STATE_SERVICE, // procstate
+ SERVICE_ADJ, // adj
+ PROCESS_CAPABILITY_NONE, // capabilities
+ TEST_APP1_NAME // packageName
+ );
+ final Intent serviceIntent = createServiceIntent(TEST_APP1_NAME, TEST_SERVICE1_NAME,
+ TEST_APP1_UID);
+ final IServiceConnection serviceConnection = mock(IServiceConnection.class);
+
+ // Make a self binding.
+ assertNotEquals(0, mAms.bindService(
+ app.getThread(), // caller
+ null, // token
+ serviceIntent, // service
+ null, // resolveType
+ serviceConnection, // connection
+ BIND_AUTO_CREATE, // flags
+ TEST_APP1_NAME, // callingPackage
+ USER_SYSTEM // userId
+ ));
+
+ verify(mAms.mOomAdjuster, bindMode).updateOomAdjPendingTargetsLocked(anyInt());
+ clearInvocations(mAms.mOomAdjuster);
+
+ // Unbind the service.
+ mAms.unbindService(serviceConnection);
+
+ verify(mAms.mOomAdjuster, unbindMode).updateOomAdjPendingTargetsLocked(anyInt());
+ clearInvocations(mAms.mOomAdjuster);
+
+ removeProcessRecord(app);
+ }
+
+ @Test
+ public void testServiceDistinctBindingOomAdjMoreImportant() throws Exception {
+ // Enable the flags.
+ mSetFlagsRule.enableFlags(Flags.FLAG_SERVICE_BINDING_OOM_ADJ_POLICY);
+
+ // Verify that there should be at least 1 oom adj update
+ // because the client is more important.
+ performTestServiceDistinctBindingOomAdj(TEST_APP1_PID, TEST_APP1_UID,
+ PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
+ PROCESS_CAPABILITY_NONE, TEST_APP1_NAME,
+ this::setHasForegroundServices,
+ TEST_APP2_PID, TEST_APP2_UID, PROCESS_STATE_HOME,
+ HOME_APP_ADJ, PROCESS_CAPABILITY_NONE, TEST_APP2_NAME, TEST_SERVICE2_NAME,
+ this::setHomeProcess,
+ BIND_AUTO_CREATE,
+ atLeastOnce(), atLeastOnce());
+
+ // Disable the flags.
+ mSetFlagsRule.disableFlags(Flags.FLAG_SERVICE_BINDING_OOM_ADJ_POLICY);
+
+ // Verify that there should be at least 1 oom adj update
+ // because the client is more important.
+ performTestServiceDistinctBindingOomAdj(TEST_APP1_PID, TEST_APP1_UID,
+ PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
+ PROCESS_CAPABILITY_NONE, TEST_APP1_NAME,
+ this::setHasForegroundServices,
+ TEST_APP2_PID, TEST_APP2_UID, PROCESS_STATE_HOME,
+ HOME_APP_ADJ, PROCESS_CAPABILITY_NONE, TEST_APP2_NAME, TEST_SERVICE2_NAME,
+ this::setHomeProcess,
+ BIND_AUTO_CREATE,
+ atLeastOnce(), atLeastOnce());
+ }
+
+ @Test
+ public void testServiceDistinctBindingOomAdjLessImportant() throws Exception {
+ // Enable the flags.
+ mSetFlagsRule.enableFlags(Flags.FLAG_SERVICE_BINDING_OOM_ADJ_POLICY);
+
+ // Verify that there should be 0 oom adj update
+ performTestServiceDistinctBindingOomAdj(TEST_APP1_PID, TEST_APP1_UID,
+ PROCESS_STATE_HOME, HOME_APP_ADJ, PROCESS_CAPABILITY_NONE, TEST_APP1_NAME,
+ this::setHomeProcess,
+ TEST_APP2_PID, TEST_APP2_UID, PROCESS_STATE_FOREGROUND_SERVICE,
+ PERCEPTIBLE_APP_ADJ, PROCESS_CAPABILITY_NONE, TEST_APP2_NAME, TEST_SERVICE2_NAME,
+ this::setHasForegroundServices,
+ BIND_AUTO_CREATE,
+ never(), never());
+
+ // Disable the flags.
+ mSetFlagsRule.disableFlags(Flags.FLAG_SERVICE_BINDING_OOM_ADJ_POLICY);
+
+ // Verify that there should be at least 1 oom adj update
+ performTestServiceDistinctBindingOomAdj(TEST_APP1_PID, TEST_APP1_UID,
+ PROCESS_STATE_HOME, HOME_APP_ADJ, PROCESS_CAPABILITY_NONE, TEST_APP1_NAME,
+ this::setHomeProcess,
+ TEST_APP2_PID, TEST_APP2_UID, PROCESS_STATE_FOREGROUND_SERVICE,
+ PERCEPTIBLE_APP_ADJ, PROCESS_CAPABILITY_NONE, TEST_APP2_NAME, TEST_SERVICE2_NAME,
+ this::setHasForegroundServices,
+ BIND_AUTO_CREATE,
+ atLeastOnce(), atLeastOnce());
+ }
+
+ @Test
+ public void testServiceDistinctBindingOomAdjWaivePriority() throws Exception {
+ // Enable the flags.
+ mSetFlagsRule.enableFlags(Flags.FLAG_SERVICE_BINDING_OOM_ADJ_POLICY);
+
+ // Verify that there should be 0 oom adj update for binding
+ // because we're using the BIND_WAIVE_PRIORITY;
+ // but for the unbinding, because client is better than service, we can't skip it safely.
+ performTestServiceDistinctBindingOomAdj(TEST_APP1_PID, TEST_APP1_UID,
+ PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
+ PROCESS_CAPABILITY_NONE, TEST_APP1_NAME,
+ this::setHasForegroundServices,
+ TEST_APP2_PID, TEST_APP2_UID, PROCESS_STATE_HOME,
+ HOME_APP_ADJ, PROCESS_CAPABILITY_NONE, TEST_APP2_NAME, TEST_SERVICE2_NAME,
+ this::setHomeProcess,
+ BIND_AUTO_CREATE | BIND_WAIVE_PRIORITY,
+ never(), atLeastOnce());
+
+ // Verify that there should be 0 oom adj update
+ // because we're using the BIND_WAIVE_PRIORITY;
+ performTestServiceDistinctBindingOomAdj(TEST_APP1_PID, TEST_APP1_UID,
+ PROCESS_STATE_HOME, HOME_APP_ADJ, PROCESS_CAPABILITY_NONE, TEST_APP1_NAME,
+ this::setHomeProcess,
+ TEST_APP2_PID, TEST_APP2_UID, PROCESS_STATE_FOREGROUND_SERVICE,
+ PERCEPTIBLE_APP_ADJ, PROCESS_CAPABILITY_NONE, TEST_APP2_NAME, TEST_SERVICE2_NAME,
+ this::setHasForegroundServices,
+ BIND_AUTO_CREATE | BIND_WAIVE_PRIORITY,
+ never(), never());
+
+ // Disable the flags.
+ mSetFlagsRule.disableFlags(Flags.FLAG_SERVICE_BINDING_OOM_ADJ_POLICY);
+
+ // Verify that there should be at least 1 oom adj update
+ // because the client is more important.
+ performTestServiceDistinctBindingOomAdj(TEST_APP1_PID, TEST_APP1_UID,
+ PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
+ PROCESS_CAPABILITY_NONE, TEST_APP1_NAME,
+ this::setHasForegroundServices,
+ TEST_APP2_PID, TEST_APP2_UID, PROCESS_STATE_HOME,
+ HOME_APP_ADJ, PROCESS_CAPABILITY_NONE, TEST_APP2_NAME, TEST_SERVICE2_NAME,
+ this::setHomeProcess,
+ BIND_AUTO_CREATE,
+ atLeastOnce(), atLeastOnce());
+ }
+
+ @Test
+ public void testServiceDistinctBindingOomAdjNoIncludeCapabilities() throws Exception {
+ // Enable the flags.
+ mSetFlagsRule.enableFlags(Flags.FLAG_SERVICE_BINDING_OOM_ADJ_POLICY);
+
+ // Verify that there should be 0 oom adj update
+ // because we didn't specify the "BIND_INCLUDE_CAPABILITIES"
+ performTestServiceDistinctBindingOomAdj(TEST_APP1_PID, TEST_APP1_UID,
+ PROCESS_STATE_HOME, HOME_APP_ADJ,
+ PROCESS_CAPABILITY_FOREGROUND_MICROPHONE, TEST_APP1_NAME,
+ this::setHomeProcess,
+ TEST_APP2_PID, TEST_APP2_UID, PROCESS_STATE_FOREGROUND_SERVICE,
+ PERCEPTIBLE_APP_ADJ, PROCESS_CAPABILITY_NONE, TEST_APP2_NAME, TEST_SERVICE2_NAME,
+ this::setHasForegroundServices,
+ BIND_AUTO_CREATE,
+ never(), never());
+
+ // Disable the flags.
+ mSetFlagsRule.disableFlags(Flags.FLAG_SERVICE_BINDING_OOM_ADJ_POLICY);
+
+ // Verify that there should be at least 1 oom adj update
+ performTestServiceDistinctBindingOomAdj(TEST_APP1_PID, TEST_APP1_UID,
+ PROCESS_STATE_HOME, HOME_APP_ADJ,
+ PROCESS_CAPABILITY_FOREGROUND_MICROPHONE, TEST_APP1_NAME,
+ this::setHomeProcess,
+ TEST_APP2_PID, TEST_APP2_UID, PROCESS_STATE_FOREGROUND_SERVICE,
+ PERCEPTIBLE_APP_ADJ, PROCESS_CAPABILITY_NONE, TEST_APP2_NAME, TEST_SERVICE2_NAME,
+ this::setHasForegroundServices,
+ BIND_AUTO_CREATE,
+ atLeastOnce(), atLeastOnce());
+ }
+
+ @Test
+ public void testServiceDistinctBindingOomAdjWithIncludeCapabilities() throws Exception {
+ // Enable the flags.
+ mSetFlagsRule.enableFlags(Flags.FLAG_SERVICE_BINDING_OOM_ADJ_POLICY);
+
+ // Verify that there should be at least 1 oom adj update
+ // because we use the "BIND_INCLUDE_CAPABILITIES"
+ performTestServiceDistinctBindingOomAdj(TEST_APP1_PID, TEST_APP1_UID,
+ PROCESS_STATE_HOME, HOME_APP_ADJ,
+ PROCESS_CAPABILITY_FOREGROUND_MICROPHONE, TEST_APP1_NAME,
+ this::setHomeProcess,
+ TEST_APP2_PID, TEST_APP2_UID, PROCESS_STATE_FOREGROUND_SERVICE,
+ PERCEPTIBLE_APP_ADJ, PROCESS_CAPABILITY_NONE, TEST_APP2_NAME, TEST_SERVICE2_NAME,
+ this::setHasForegroundServices,
+ BIND_AUTO_CREATE | BIND_INCLUDE_CAPABILITIES,
+ atLeastOnce(), atLeastOnce());
+
+ // Disable the flags.
+ mSetFlagsRule.disableFlags(Flags.FLAG_SERVICE_BINDING_OOM_ADJ_POLICY);
+
+ // Verify that there should be at least 1 oom adj update
+ performTestServiceDistinctBindingOomAdj(TEST_APP1_PID, TEST_APP1_UID,
+ PROCESS_STATE_HOME, HOME_APP_ADJ,
+ PROCESS_CAPABILITY_FOREGROUND_MICROPHONE, TEST_APP1_NAME,
+ this::setHomeProcess,
+ TEST_APP2_PID, TEST_APP2_UID, PROCESS_STATE_FOREGROUND_SERVICE,
+ PERCEPTIBLE_APP_ADJ, PROCESS_CAPABILITY_NONE, TEST_APP2_NAME, TEST_SERVICE2_NAME,
+ this::setHasForegroundServices,
+ BIND_AUTO_CREATE | BIND_INCLUDE_CAPABILITIES,
+ atLeastOnce(), atLeastOnce());
+ }
+
+ @Test
+ public void testServiceDistinctBindingOomAdjFreezeCaller() throws Exception {
+ // Enable the flags.
+ mSetFlagsRule.enableFlags(Flags.FLAG_SERVICE_BINDING_OOM_ADJ_POLICY);
+
+ // Verify that there should be 0 oom adj update
+ performTestServiceDistinctBindingOomAdj(TEST_APP1_PID, TEST_APP1_UID,
+ PROCESS_STATE_CACHED_EMPTY, CACHED_APP_MIN_ADJ, PROCESS_CAPABILITY_NONE,
+ TEST_APP1_NAME, null,
+ TEST_APP2_PID, TEST_APP2_UID, PROCESS_STATE_FOREGROUND_SERVICE,
+ PERCEPTIBLE_APP_ADJ, PROCESS_CAPABILITY_NONE, TEST_APP2_NAME, TEST_SERVICE2_NAME,
+ this::setHasForegroundServices,
+ BIND_AUTO_CREATE,
+ never(), never());
+
+ // Disable the flags.
+ mSetFlagsRule.disableFlags(Flags.FLAG_SERVICE_BINDING_OOM_ADJ_POLICY);
+
+ // Verify that there should be at least 1 oom adj update
+ performTestServiceDistinctBindingOomAdj(TEST_APP1_PID, TEST_APP1_UID,
+ PROCESS_STATE_CACHED_EMPTY, CACHED_APP_MIN_ADJ, PROCESS_CAPABILITY_NONE,
+ TEST_APP1_NAME, null,
+ TEST_APP2_PID, TEST_APP2_UID, PROCESS_STATE_FOREGROUND_SERVICE,
+ PERCEPTIBLE_APP_ADJ, PROCESS_CAPABILITY_NONE, TEST_APP2_NAME, TEST_SERVICE2_NAME,
+ this::setHasForegroundServices,
+ BIND_AUTO_CREATE,
+ atLeastOnce(), atLeastOnce());
+ }
+
+ @SuppressWarnings("GuardedBy")
+ private void performTestServiceDistinctBindingOomAdj(int clientPid, int clientUid,
+ int clientProcState, int clientAdj, int clientCap, String clientPackageName,
+ Consumer<ProcessRecord> clientAppFixer,
+ int servicePid, int serviceUid, int serviceProcState, int serviceAdj,
+ int serviceCap, String servicePackageName, String serviceName,
+ Consumer<ProcessRecord> serviceAppFixer, int bindingFlags,
+ VerificationMode bindMode, VerificationMode unbindMode) throws Exception {
+ final ProcessRecord clientApp = addProcessRecord(
+ clientPid,
+ clientUid,
+ clientProcState,
+ clientAdj,
+ clientCap,
+ clientPackageName
+ );
+ final ProcessRecord serviceApp = addProcessRecord(
+ servicePid,
+ serviceUid,
+ serviceProcState,
+ serviceAdj,
+ serviceCap,
+ servicePackageName
+ );
+ final Intent serviceIntent = createServiceIntent(servicePackageName, serviceName,
+ serviceUid);
+ final IServiceConnection serviceConnection = mock(IServiceConnection.class);
+ if (clientAppFixer != null) clientAppFixer.accept(clientApp);
+ if (serviceAppFixer != null) serviceAppFixer.accept(serviceApp);
+
+ // Make a self binding.
+ assertNotEquals(0, mAms.bindService(
+ clientApp.getThread(), // caller
+ null, // token
+ serviceIntent, // service
+ null, // resolveType
+ serviceConnection, // connection
+ bindingFlags, // flags
+ clientPackageName, // callingPackage
+ USER_SYSTEM // userId
+ ));
+
+ verify(mAms.mOomAdjuster, bindMode).updateOomAdjPendingTargetsLocked(anyInt());
+ clearInvocations(mAms.mOomAdjuster);
+
+ if (clientApp.isFreezable()) {
+ verify(mAms.mOomAdjuster.mCachedAppOptimizer,
+ times(Flags.serviceBindingOomAdjPolicy() ? 1 : 0))
+ .freezeAppAsyncInternalLSP(eq(clientApp), eq(0L), anyBoolean());
+ clearInvocations(mAms.mOomAdjuster.mCachedAppOptimizer);
+ }
+
+ // Unbind the service.
+ mAms.unbindService(serviceConnection);
+
+ verify(mAms.mOomAdjuster, unbindMode).updateOomAdjPendingTargetsLocked(anyInt());
+ clearInvocations(mAms.mOomAdjuster);
+
+ removeProcessRecord(clientApp);
+ removeProcessRecord(serviceApp);
+ }
+
+ private void setHasForegroundServices(ProcessRecord app) {
+ app.mServices.setHasForegroundServices(true,
+ FOREGROUND_SERVICE_TYPE_SYSTEM_EXEMPTED, false);
+ }
+
+ private void setHomeProcess(ProcessRecord app) {
+ final WindowProcessController wpc = app.getWindowProcessController();
+ doReturn(true).when(wpc).isHomeProcess();
+ }
+
+ @SuppressWarnings("GuardedBy")
+ private ProcessRecord addProcessRecord(int pid, int uid, int procState, int adj, int cap,
+ String packageName) {
+ final IApplicationThread appThread = mock(IApplicationThread.class);
+ final IBinder threadBinder = mock(IBinder.class);
+ final ProcessRecord app = makeProcessRecord(pid, uid, uid, null, 0,
+ procState, adj, cap, 0L, 0L, packageName, packageName, mAms);
+
+ app.makeActive(appThread, mAms.mProcessStats);
+ doReturn(threadBinder).when(appThread).asBinder();
+ mProcessList.addProcessNameLocked(app);
+ mProcessList.updateLruProcessLocked(app, false, null);
+
+ setFieldValue(ProcessRecord.class, app, "mWindowProcessController",
+ mock(WindowProcessController.class));
+
+ doReturn(app.getSetCapability()).when(mAms.mOomAdjuster).getDefaultCapability(
+ eq(app), anyInt());
+
+ return app;
+ }
+
+ @SuppressWarnings("GuardedBy")
+ private Intent createServiceIntent(String packageName, String serviceName, int serviceUid) {
+ final ComponentName compName = new ComponentName(packageName, serviceName);
+ final Intent serviceIntent = new Intent().setComponent(compName);
+ final ResolveInfo rInfo = new ResolveInfo();
+ rInfo.serviceInfo = makeServiceInfo(compName.getClassName(), compName.getPackageName(),
+ serviceUid);
+ doReturn(rInfo).when(mPackageManagerInt).resolveService(any(Intent.class), any(),
+ anyLong(), anyInt(), anyInt());
+
+ return serviceIntent;
+ }
+
+ @SuppressWarnings("GuardedBy")
+ private void removeProcessRecord(ProcessRecord app) {
+ app.setKilled(true);
+ mProcessList.removeProcessNameLocked(app.processName, app.uid);
+ mProcessList.removeLruProcessLocked(app);
+ }
+
+ @SuppressWarnings("GuardedBy")
+ private ProcessRecord makeProcessRecord(int pid, int uid, int packageUid, Integer definingUid,
+ int connectionGroup, int procState, int adj, int cap, long pss, long rss,
+ String processName, String packageName, ActivityManagerService ams) {
+ final ProcessRecord app = ApplicationExitInfoTest.makeProcessRecord(pid, uid, packageUid,
+ definingUid, connectionGroup, procState, pss, rss, processName, packageName, ams);
+ app.mState.setCurProcState(procState);
+ app.mState.setSetProcState(procState);
+ app.mState.setCurAdj(adj);
+ app.mState.setSetAdj(adj);
+ app.mState.setCurCapability(cap);
+ app.mState.setSetCapability(cap);
+ app.mState.setCached(procState >= PROCESS_STATE_LAST_ACTIVITY || adj >= CACHED_APP_MIN_ADJ);
+ return app;
+ }
+
+ @SuppressWarnings("GuardedBy")
+ private ServiceInfo makeServiceInfo(String serviceName, String packageName, int packageUid) {
+ final ServiceInfo sInfo = new ServiceInfo();
+ sInfo.name = serviceName;
+ sInfo.processName = packageName;
+ sInfo.packageName = packageName;
+ sInfo.applicationInfo = new ApplicationInfo();
+ sInfo.applicationInfo.uid = packageUid;
+ sInfo.applicationInfo.packageName = packageName;
+ sInfo.exported = true;
+ return sInfo;
+ }
+
+ private static <T> void setFieldValue(Class clazz, Object obj, String fieldName, T val) {
+ try {
+ Field field = clazz.getDeclaredField(fieldName);
+ field.setAccessible(true);
+ Field mfield = Field.class.getDeclaredField("accessFlags");
+ mfield.setAccessible(true);
+ mfield.setInt(field, mfield.getInt(field) & ~(Modifier.FINAL | Modifier.PRIVATE));
+ field.set(obj, val);
+ } catch (NoSuchFieldException | IllegalAccessException e) {
+ }
+ }
+
+ private class TestInjector extends Injector {
+ TestInjector(Context context) {
+ super(context);
+ }
+
+ @Override
+ public AppOpsService getAppOpsService(File recentAccessesFile, File storageFile,
+ Handler handler) {
+ return mAppOpsService;
+ }
+
+ @Override
+ public Handler getUiHandler(ActivityManagerService service) {
+ return mHandlerThread.getThreadHandler();
+ }
+
+ @Override
+ public ProcessList getProcessList(ActivityManagerService service) {
+ return mProcessList;
+ }
+
+ @Override
+ public ActiveServices getActiveServices(ActivityManagerService service) {
+ if (mActiveServices == null) {
+ mActiveServices = spy(new ActiveServices(service));
+ }
+ return mActiveServices;
+ }
+
+ @Override
+ public int getCallingUid() {
+ return mCurrentCallingUid;
+ }
+
+ @Override
+ public int getCallingPid() {
+ return mCurrentCallingPid;
+ }
+
+ @Override
+ public long clearCallingIdentity() {
+ return (((long) mCurrentCallingUid) << 32) | mCurrentCallingPid;
+ }
+
+ @Override
+ public void restoreCallingIdentity(long ident) {
+ }
+
+ @Override
+ public AppErrors getAppErrors() {
+ return mAppErrors;
+ }
+
+ @Override
+ public IntentFirewall getIntentFirewall() {
+ return mIntentFirewall;
+ }
+ }
+
+ // TODO: [b/302724778] Remove manual JNI load
+ static {
+ System.loadLibrary("mockingservicestestjni");
+ }
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java
index 293391f..c6608e6 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/JobStatusTest.java
@@ -45,6 +45,7 @@
import static com.android.server.job.controllers.JobStatus.NO_EARLIEST_RUNTIME;
import static com.android.server.job.controllers.JobStatus.NO_LATEST_RUNTIME;
+import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@@ -78,6 +79,7 @@
import java.time.Clock;
import java.time.ZoneOffset;
+import java.util.Arrays;
@RunWith(AndroidJUnit4.class)
public class JobStatusTest {
@@ -138,6 +140,35 @@
}
@Test
+ public void testApplyBasicPiiFilters_email() {
+ assertEquals("[EMAIL]", JobStatus.applyBasicPiiFilters("test@email.com"));
+ assertEquals("[EMAIL]", JobStatus.applyBasicPiiFilters("test+plus@email.com"));
+ assertEquals("[EMAIL]", JobStatus.applyBasicPiiFilters("t.e_st+plus-minus@email.com"));
+
+ assertEquals("prefix:[EMAIL]", JobStatus.applyBasicPiiFilters("prefix:test@email.com"));
+
+ assertEquals("not-an-email", JobStatus.applyBasicPiiFilters("not-an-email"));
+ }
+
+ @Test
+ public void testApplyBasicPiiFilters_mixture() {
+ assertEquals("[PHONE]:[EMAIL]",
+ JobStatus.applyBasicPiiFilters("123-456-7890:test+plus@email.com"));
+ assertEquals("prefix:[PHONE]:[EMAIL]",
+ JobStatus.applyBasicPiiFilters("prefix:123-456-7890:test+plus@email.com"));
+ }
+
+ @Test
+ public void testApplyBasicPiiFilters_phone() {
+ assertEquals("[PHONE]", JobStatus.applyBasicPiiFilters("123-456-7890"));
+ assertEquals("[PHONE]", JobStatus.applyBasicPiiFilters("+1-234-567-8900"));
+
+ assertEquals("prefix:[PHONE]", JobStatus.applyBasicPiiFilters("prefix:123-456-7890"));
+
+ assertEquals("not-a-phone-number", JobStatus.applyBasicPiiFilters("not-a-phone-number"));
+ }
+
+ @Test
public void testCanRunInBatterySaver_regular() {
final JobInfo jobInfo =
new JobInfo.Builder(101, new ComponentName("foo", "bar")).build();
@@ -245,6 +276,42 @@
}
@Test
+ public void testGetFilteredDebugTags() {
+ final JobInfo jobInfo = new JobInfo.Builder(101, new ComponentName("foo", "bar"))
+ .addDebugTag("test@email.com")
+ .addDebugTag("123-456-7890")
+ .addDebugTag("random")
+ .build();
+ JobStatus job = createJobStatus(jobInfo);
+ String[] expected = new String[]{"[EMAIL]", "[PHONE]", "random"};
+ String[] result = job.getFilteredDebugTags();
+ Arrays.sort(expected);
+ Arrays.sort(result);
+ assertArrayEquals(expected, result);
+ }
+
+ @Test
+ public void testGetFilteredTraceTag() {
+ JobInfo jobInfo = new JobInfo.Builder(101, new ComponentName("foo", "bar"))
+ .setTraceTag("test@email.com")
+ .build();
+ JobStatus job = createJobStatus(jobInfo);
+ assertEquals("[EMAIL]", job.getFilteredTraceTag());
+
+ jobInfo = new JobInfo.Builder(101, new ComponentName("foo", "bar"))
+ .setTraceTag("123-456-7890")
+ .build();
+ job = createJobStatus(jobInfo);
+ assertEquals("[PHONE]", job.getFilteredTraceTag());
+
+ jobInfo = new JobInfo.Builder(101, new ComponentName("foo", "bar"))
+ .setTraceTag("random")
+ .build();
+ job = createJobStatus(jobInfo);
+ assertEquals("random", job.getFilteredTraceTag());
+ }
+
+ @Test
public void testIsUserVisibleJob() {
JobInfo jobInfo = new JobInfo.Builder(101, new ComponentName("foo", "bar"))
.setUserInitiated(false)
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/altitude/AltitudeConverterTest.java b/services/tests/mockingservicestests/src/com/android/server/location/altitude/AltitudeConverterTest.java
index 8d9a6c5..9a143d5 100644
--- a/services/tests/mockingservicestests/src/com/android/server/location/altitude/AltitudeConverterTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/location/altitude/AltitudeConverterTest.java
@@ -21,6 +21,8 @@
import static org.junit.Assert.assertThrows;
import android.content.Context;
+import android.frameworks.location.altitude.GetGeoidHeightRequest;
+import android.frameworks.location.altitude.GetGeoidHeightResponse;
import android.location.Location;
import android.location.altitude.AltitudeConverter;
@@ -176,4 +178,20 @@
assertThrows(IllegalArgumentException.class,
() -> mAltitudeConverter.addMslAltitudeToLocation(mContext, location));
}
+
+ @Test
+ public void testGetGeoidHeight_expectedBehavior() throws IOException {
+ GetGeoidHeightRequest request = new GetGeoidHeightRequest();
+ request.latitudeDegrees = -35.334815;
+ request.longitudeDegrees = -45;
+ // Requires data to be loaded from raw assets.
+ GetGeoidHeightResponse response = mAltitudeConverter.getGeoidHeight(mContext, request);
+ assertThat(response.geoidHeightMeters).isWithin(2).of(-5.0622);
+ assertThat(response.geoidHeightErrorMeters).isGreaterThan(0f);
+ assertThat(response.geoidHeightErrorMeters).isLessThan(1f);
+ assertThat(response.expirationDistanceMeters).isWithin(1).of(-6.33);
+ assertThat(response.additionalGeoidHeightErrorMeters).isGreaterThan(0f);
+ assertThat(response.additionalGeoidHeightErrorMeters).isLessThan(1f);
+ assertThat(response.success).isTrue();
+ }
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/provider/StationaryThrottlingLocationProviderTest.java b/services/tests/mockingservicestests/src/com/android/server/location/provider/StationaryThrottlingLocationProviderTest.java
index 4eba219..efab19c 100644
--- a/services/tests/mockingservicestests/src/com/android/server/location/provider/StationaryThrottlingLocationProviderTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/location/provider/StationaryThrottlingLocationProviderTest.java
@@ -29,6 +29,7 @@
import android.content.Context;
import android.location.Location;
+import android.location.LocationRequest;
import android.location.LocationResult;
import android.location.provider.ProviderRequest;
import android.platform.test.annotations.Presubmit;
@@ -218,4 +219,22 @@
verify(mDelegate, never()).onSetRequest(ProviderRequest.EMPTY_REQUEST);
verify(mListener, after(75).times(1)).onReportLocation(any(LocationResult.class));
}
+
+ @Test
+ public void testNoThrottle_highAccuracy() {
+ ProviderRequest request = new ProviderRequest.Builder().setIntervalMillis(
+ 50).setQuality(LocationRequest.QUALITY_HIGH_ACCURACY).build();
+
+ mProvider.getController().setRequest(request);
+ verify(mDelegate).onSetRequest(request);
+
+ LocationResult loc = createLocationResult("test_provider", mRandom);
+ mDelegateProvider.reportLocation(loc);
+ verify(mListener, times(1)).onReportLocation(loc);
+
+ mInjector.getDeviceStationaryHelper().setStationary(true);
+ mInjector.getDeviceIdleHelper().setIdle(true);
+ verify(mDelegate, never()).onSetRequest(ProviderRequest.EMPTY_REQUEST);
+ verify(mListener, after(75).times(1)).onReportLocation(any(LocationResult.class));
+ }
}
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsHistoryTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsHistoryTest.java
index bb70080..9251376 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsHistoryTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsHistoryTest.java
@@ -21,6 +21,9 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import android.content.Context;
@@ -96,18 +99,11 @@
mClock.realtime = 123;
mHistory = new BatteryStatsHistory(mHistoryBuffer, mSystemDir, 32, 1024,
- mStepDetailsCalculator, mClock, mMonotonicClock, mTracer) {
- @Override
- public boolean readFileToParcel(Parcel out, AtomicFile file) {
- mReadFiles.add(file.getBaseFile().getName());
- return super.readFileToParcel(out, file);
- }
- };
+ mStepDetailsCalculator, mClock, mMonotonicClock, mTracer);
when(mStepDetailsCalculator.getHistoryStepDetails())
.thenReturn(new BatteryStats.HistoryStepDetails());
-
mHistoryPrinter = new BatteryStats.HistoryPrinter();
}
@@ -276,6 +272,15 @@
mReadFiles.clear();
+ // Make an immutable copy and spy on it
+ mHistory = spy(mHistory.copy());
+
+ doAnswer(invocation -> {
+ AtomicFile file = invocation.getArgument(1);
+ mReadFiles.add(file.getBaseFile().getName());
+ return invocation.callRealMethod();
+ }).when(mHistory).readFileToParcel(any(), any());
+
// Prepare history for iteration
mHistory.iterate(0, MonotonicClock.UNDEFINED);
@@ -309,6 +314,15 @@
mReadFiles.clear();
+ // Make an immutable copy and spy on it
+ mHistory = spy(mHistory.copy());
+
+ doAnswer(invocation -> {
+ AtomicFile file = invocation.getArgument(1);
+ mReadFiles.add(file.getBaseFile().getName());
+ return invocation.callRealMethod();
+ }).when(mHistory).readFileToParcel(any(), any());
+
// Prepare history for iteration
mHistory.iterate(1000, 3000);
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/SystemServicePowerCalculatorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/SystemServicePowerCalculatorTest.java
index 4dae2d5..8e53d52 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/SystemServicePowerCalculatorTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/SystemServicePowerCalculatorTest.java
@@ -28,6 +28,9 @@
import android.os.BatteryConsumer;
import android.os.Binder;
import android.os.Process;
+import android.platform.test.annotations.RequiresFlagsDisabled;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -38,6 +41,7 @@
import com.android.internal.os.KernelSingleUidTimeReader;
import com.android.internal.os.PowerProfile;
import com.android.internal.power.EnergyConsumerStats;
+import com.android.server.power.optimization.Flags;
import org.junit.Before;
import org.junit.Rule;
@@ -54,6 +58,8 @@
@RunWith(AndroidJUnit4.class)
@SuppressWarnings("GuardedBy")
public class SystemServicePowerCalculatorTest {
+ @Rule
+ public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
private static final double PRECISION = 0.000001;
private static final int APP_UID1 = 100;
@@ -108,6 +114,7 @@
}
@Test
+ @RequiresFlagsDisabled(Flags.FLAG_DISABLE_SYSTEM_SERVICE_POWER_ATTR)
public void testPowerProfileBasedModel() {
prepareBatteryStats(null);
@@ -135,6 +142,7 @@
}
@Test
+ @RequiresFlagsDisabled(Flags.FLAG_DISABLE_SYSTEM_SERVICE_POWER_ATTR)
public void testMeasuredEnergyBasedModel() {
final boolean[] supportedPowerBuckets =
new boolean[EnergyConsumerStats.NUMBER_STANDARD_POWER_BUCKETS];
diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp
index 8958fac..e22d99d 100644
--- a/services/tests/servicestests/Android.bp
+++ b/services/tests/servicestests/Android.bp
@@ -36,6 +36,7 @@
"-Werror",
],
static_libs: [
+ "cts-input-lib",
"frameworks-base-testutils",
"services.accessibility",
"services.appwidget",
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityInputFilterInputTest.kt b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityInputFilterInputTest.kt
new file mode 100644
index 0000000..52c7d8d
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityInputFilterInputTest.kt
@@ -0,0 +1,280 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.accessibility
+
+import android.hardware.display.DisplayManagerGlobal
+import android.os.SystemClock
+import android.view.Display
+import android.view.Display.DEFAULT_DISPLAY
+import android.view.DisplayAdjustments
+import android.view.DisplayInfo
+import android.view.IInputFilterHost
+import android.view.InputDevice.SOURCE_TOUCHSCREEN
+import android.view.InputEvent
+import android.view.MotionEvent
+import android.view.MotionEvent.ACTION_DOWN
+import android.view.MotionEvent.ACTION_MOVE
+import android.view.MotionEvent.ACTION_UP
+import android.view.MotionEvent.ACTION_HOVER_ENTER
+import android.view.MotionEvent.ACTION_HOVER_EXIT
+import android.view.MotionEvent.ACTION_HOVER_MOVE
+import android.view.WindowManagerPolicyConstants.FLAG_PASS_TO_USER
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.cts.input.inputeventmatchers.withDeviceId
+import com.android.cts.input.inputeventmatchers.withMotionAction
+import com.android.server.LocalServices
+import com.android.server.accessibility.magnification.MagnificationProcessor
+import com.android.server.wm.WindowManagerInternal
+import java.util.concurrent.LinkedBlockingQueue
+import org.hamcrest.Matchers.allOf
+import org.junit.After
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.any
+import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.Mock
+import org.mockito.Mockito
+import org.mockito.Mockito.doAnswer
+import org.mockito.Mockito.`when`
+import org.mockito.junit.MockitoJUnit
+import org.mockito.junit.MockitoRule
+import org.mockito.stubbing.OngoingStubbing
+
+
+/**
+ * Create a MotionEvent with the provided action, eventTime, and source
+ */
+fun createMotionEvent(action: Int, downTime: Long, eventTime: Long, source: Int, deviceId: Int):
+ MotionEvent {
+ val x = 1f
+ val y = 2f
+ val pressure = 3f
+ val size = 1f
+ val metaState = 0
+ val xPrecision = 0f
+ val yPrecision = 0f
+ val edgeFlags = 0
+ val displayId = 0
+ return MotionEvent.obtain(downTime, eventTime, action, x, y, pressure, size, metaState,
+ xPrecision, yPrecision, deviceId, edgeFlags, source, displayId)
+}
+
+/**
+ * Tests for AccessibilityInputFilter, focusing on the input event processing as seen by the callers
+ * of the InputFilter interface.
+ * The main interaction with AccessibilityInputFilter in these tests is with the filterInputEvent
+ * and sendInputEvent APIs of InputFilter.
+ */
+@RunWith(AndroidJUnit4::class)
+class AccessibilityInputFilterInputTest {
+ private val instrumentation = InstrumentationRegistry.getInstrumentation()
+
+ private companion object{
+ const val ALL_A11Y_FEATURES = (AccessibilityInputFilter.FLAG_FEATURE_AUTOCLICK
+ or AccessibilityInputFilter.FLAG_FEATURE_TOUCH_EXPLORATION
+ or AccessibilityInputFilter.FLAG_FEATURE_CONTROL_SCREEN_MAGNIFIER
+ or AccessibilityInputFilter.FLAG_FEATURE_TRIGGERED_SCREEN_MAGNIFIER
+ or AccessibilityInputFilter.FLAG_FEATURE_INJECT_MOTION_EVENTS
+ or AccessibilityInputFilter.FLAG_FEATURE_FILTER_KEY_EVENTS)
+ }
+
+ @Rule
+ @JvmField
+ val mocks: MockitoRule = MockitoJUnit.rule()
+
+ @Mock
+ private lateinit var mockA11yController: WindowManagerInternal.AccessibilityControllerInternal
+
+ @Mock
+ private lateinit var mockWindowManagerService: WindowManagerInternal
+
+ @Mock
+ private lateinit var mockMagnificationProcessor: MagnificationProcessor
+
+ private val inputEvents = LinkedBlockingQueue<InputEvent>()
+ private val verifier = BlockingQueueEventVerifier(inputEvents)
+
+ @Mock
+ private lateinit var host: IInputFilterHost
+ private lateinit var ams: AccessibilityManagerService
+ private lateinit var a11yInputFilter: AccessibilityInputFilter
+ private val touchDeviceId = 1
+
+ @Before
+ fun setUp() {
+ val context = instrumentation.context
+ LocalServices.removeServiceForTest(WindowManagerInternal::class.java)
+ LocalServices.addService(WindowManagerInternal::class.java, mockWindowManagerService)
+
+ whenever(mockA11yController.isAccessibilityTracingEnabled).thenReturn(false)
+ whenever(
+ mockWindowManagerService.accessibilityController).thenReturn(
+ mockA11yController)
+
+ ams = Mockito.spy(AccessibilityManagerService(context))
+ val displayList = arrayListOf(createStubDisplay(DEFAULT_DISPLAY, DisplayInfo()))
+ whenever(ams.validDisplayList).thenReturn(displayList)
+ whenever(ams.magnificationProcessor).thenReturn(mockMagnificationProcessor)
+
+ doAnswer {
+ val event = it.getArgument(0) as MotionEvent
+ inputEvents.add(MotionEvent.obtain(event))
+ }.`when`(host).sendInputEvent(any(), anyInt())
+
+ a11yInputFilter = AccessibilityInputFilter(context, ams)
+ a11yInputFilter.install(host)
+ }
+
+ @After
+ fun tearDown() {
+ if (this::a11yInputFilter.isInitialized) {
+ a11yInputFilter.uninstall()
+ }
+ }
+
+ /**
+ * When no features are enabled, the events pass through the filter without getting modified.
+ */
+ @Test
+ fun testSingleDeviceTouchEventsWithoutA11yFeatures() {
+ enableFeatures(0)
+
+ val downTime = SystemClock.uptimeMillis()
+ val downEvent = createMotionEvent(
+ ACTION_DOWN, downTime, downTime, SOURCE_TOUCHSCREEN, touchDeviceId)
+ send(downEvent)
+ verifier.assertReceivedMotion(
+ allOf(withMotionAction(ACTION_DOWN), withDeviceId(touchDeviceId)))
+
+ val moveEvent = createMotionEvent(
+ ACTION_MOVE, downTime, SystemClock.uptimeMillis(), SOURCE_TOUCHSCREEN, touchDeviceId)
+ send(moveEvent)
+ verifier.assertReceivedMotion(
+ allOf(withMotionAction(ACTION_MOVE), withDeviceId(touchDeviceId)))
+
+ val upEvent = createMotionEvent(
+ ACTION_UP, downTime, SystemClock.uptimeMillis(), SOURCE_TOUCHSCREEN, touchDeviceId)
+ send(upEvent)
+ verifier.assertReceivedMotion(
+ allOf(withMotionAction(ACTION_UP), withDeviceId(touchDeviceId)))
+
+ verifier.assertNoEvents()
+ }
+
+ /**
+ * Enable all a11y features and send a touchscreen stream of DOWN -> MOVE -> UP events.
+ * These get converted into HOVER_ENTER -> HOVER_MOVE -> HOVER_EXIT events by the input filter.
+ */
+ @Test
+ fun testSingleDeviceTouchEventsWithAllA11yFeatures() {
+ enableFeatures(ALL_A11Y_FEATURES)
+
+ val downTime = SystemClock.uptimeMillis()
+ val downEvent = createMotionEvent(
+ ACTION_DOWN, downTime, downTime, SOURCE_TOUCHSCREEN, touchDeviceId)
+ send(MotionEvent.obtain(downEvent))
+
+ // DOWN event gets transformed to HOVER_ENTER
+ verifier.assertReceivedMotion(
+ allOf(withMotionAction(ACTION_HOVER_ENTER), withDeviceId(touchDeviceId)))
+
+ // MOVE becomes HOVER_MOVE
+ val moveEvent = createMotionEvent(
+ ACTION_MOVE, downTime, SystemClock.uptimeMillis(), SOURCE_TOUCHSCREEN, touchDeviceId)
+ send(moveEvent)
+ verifier.assertReceivedMotion(
+ allOf(withMotionAction(ACTION_HOVER_MOVE), withDeviceId(touchDeviceId)))
+
+ // UP becomes HOVER_EXIT
+ val upEvent = createMotionEvent(
+ ACTION_UP, downTime, SystemClock.uptimeMillis(), SOURCE_TOUCHSCREEN, touchDeviceId)
+ send(upEvent)
+
+ verifier.assertReceivedMotion(
+ allOf(withMotionAction(ACTION_HOVER_EXIT), withDeviceId(touchDeviceId)))
+
+ verifier.assertNoEvents()
+ }
+
+ /**
+ * Enable all a11y features and send a touchscreen event stream. In the middle of the gesture,
+ * disable the a11y features.
+ * When the a11y features are disabled, the filter generates HOVER_EXIT without further input
+ * from the dispatcher.
+ */
+ @Test
+ fun testSingleDeviceTouchEventsDisableFeaturesMidGesture() {
+ enableFeatures(ALL_A11Y_FEATURES)
+
+ val downTime = SystemClock.uptimeMillis()
+ val downEvent = createMotionEvent(
+ ACTION_DOWN, downTime, downTime, SOURCE_TOUCHSCREEN, touchDeviceId)
+ send(MotionEvent.obtain(downEvent))
+
+ // DOWN event gets transformed to HOVER_ENTER
+ verifier.assertReceivedMotion(
+ allOf(withMotionAction(ACTION_HOVER_ENTER), withDeviceId(touchDeviceId)))
+ verifier.assertNoEvents()
+
+ enableFeatures(0)
+ verifier.assertReceivedMotion(
+ allOf(withMotionAction(ACTION_HOVER_EXIT), withDeviceId(touchDeviceId)))
+ verifier.assertNoEvents()
+
+ val moveEvent = createMotionEvent(
+ ACTION_MOVE, downTime, SystemClock.uptimeMillis(), SOURCE_TOUCHSCREEN, touchDeviceId)
+ send(moveEvent)
+ val upEvent = createMotionEvent(
+ ACTION_UP, downTime, SystemClock.uptimeMillis(), SOURCE_TOUCHSCREEN, touchDeviceId)
+ send(upEvent)
+ // As the original gesture continues, no additional events should be getting sent by the
+ // filter because the HOVER_EXIT above already effectively finished the current gesture and
+ // the DOWN event was never sent to the host.
+
+ // Bug: the down event was swallowed, so the remainder of the gesture should be swallowed
+ // too. However, the MOVE and UP events are currently passed back to the dispatcher.
+ // TODO(b/310014874) - ensure a11y sends consistent input streams to the dispatcher
+ verifier.assertReceivedMotion(
+ allOf(withMotionAction(ACTION_MOVE), withDeviceId(touchDeviceId)))
+ verifier.assertReceivedMotion(
+ allOf(withMotionAction(ACTION_UP), withDeviceId(touchDeviceId)))
+
+ verifier.assertNoEvents()
+ }
+
+ private fun createStubDisplay(displayId: Int, displayInfo: DisplayInfo): Display {
+ val display = Display(DisplayManagerGlobal.getInstance(), displayId,
+ displayInfo, DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS)
+ return display
+ }
+
+ private fun send(event: InputEvent) {
+ // We need to make a copy of the event before sending it to the filter, because the filter
+ // will recycle it, but the caller of this function might want to still be able to use
+ // this event for subsequent checks
+ val eventCopy = if (event is MotionEvent) MotionEvent.obtain(event) else event
+ a11yInputFilter.filterInputEvent(eventCopy, FLAG_PASS_TO_USER)
+ }
+
+ private fun enableFeatures(features: Int) {
+ instrumentation.runOnMainSync { a11yInputFilter.setUserAndEnabledFeatures(0, features) }
+ }
+}
+
+private fun <T> whenever(methodCall: T): OngoingStubbing<T> = `when`(methodCall)
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/BlockingQueueEventVerifier.kt b/services/tests/servicestests/src/com/android/server/accessibility/BlockingQueueEventVerifier.kt
new file mode 100644
index 0000000..b12f537
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/accessibility/BlockingQueueEventVerifier.kt
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.accessibility
+
+import android.os.InputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS
+import android.view.InputEvent
+import android.view.MotionEvent
+import java.time.Duration
+import java.util.concurrent.BlockingQueue
+import java.util.concurrent.TimeUnit
+import org.junit.Assert.fail
+
+import org.hamcrest.Matcher
+import org.hamcrest.MatcherAssert.assertThat
+import org.junit.Assert.assertNull
+
+private fun <T> getEvent(queue: BlockingQueue<T>, timeout: Duration): T? {
+ return queue.poll(timeout.toMillis(), TimeUnit.MILLISECONDS)
+}
+
+class BlockingQueueEventVerifier(val queue: BlockingQueue<InputEvent>) {
+ fun assertReceivedMotion(matcher: Matcher<MotionEvent>) {
+ val event = getMotionEvent()
+ assertThat("MotionEvent checks", event, matcher)
+ }
+
+ fun assertNoEvents() {
+ val event = getEvent(queue, Duration.ofMillis(50))
+ assertNull(event)
+ }
+
+ private fun getMotionEvent(): MotionEvent {
+ val event = getEvent(queue, Duration.ofMillis(DEFAULT_DISPATCHING_TIMEOUT_MILLIS.toLong()))
+ if (event == null) {
+ fail("Did not get an event")
+ }
+ if (event is MotionEvent) {
+ return event
+ }
+ fail("Instead of motion, got $event")
+ throw RuntimeException("should not reach here")
+ }
+}
+
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/UserAwareBiometricSchedulerTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/UserAwareBiometricSchedulerTest.java
index 0815fe5..dd5d826 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/UserAwareBiometricSchedulerTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/UserAwareBiometricSchedulerTest.java
@@ -33,6 +33,9 @@
import android.os.IBinder;
import android.os.UserHandle;
import android.platform.test.annotations.Presubmit;
+import android.platform.test.annotations.RequiresFlagsDisabled;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
@@ -40,6 +43,7 @@
import androidx.annotation.Nullable;
import androidx.test.filters.SmallTest;
+import com.android.server.biometrics.Flags;
import com.android.server.biometrics.log.BiometricContext;
import com.android.server.biometrics.log.BiometricLogger;
@@ -66,6 +70,9 @@
@Rule
public final MockitoRule mockito = MockitoJUnit.rule();
+ @Rule
+ public final CheckFlagsRule mCheckFlagsRule =
+ DeviceFlagsValueProvider.createCheckFlagsRule();
private Handler mHandler;
private UserAwareBiometricScheduler mScheduler;
@@ -122,6 +129,7 @@
}
@Test
+ @RequiresFlagsDisabled(Flags.FLAG_DE_HIDL)
public void testScheduleOperation_whenNoUser() {
mCurrentUserId = UserHandle.USER_NULL;
@@ -183,6 +191,7 @@
}
@Test
+ @RequiresFlagsDisabled(Flags.FLAG_DE_HIDL)
public void testScheduleOperation_whenSameUser() {
mCurrentUserId = 10;
@@ -199,6 +208,7 @@
}
@Test
+ @RequiresFlagsDisabled(Flags.FLAG_DE_HIDL)
public void testScheduleOperation_whenDifferentUser() {
mCurrentUserId = 10;
@@ -219,6 +229,7 @@
}
@Test
+ @RequiresFlagsDisabled(Flags.FLAG_DE_HIDL)
public void testStartUser_alwaysStartsNextOperation() {
BaseClientMonitor nextClient = mock(BaseClientMonitor.class);
when(nextClient.getTargetUserId()).thenReturn(10);
@@ -246,6 +257,7 @@
}
@Test
+ @RequiresFlagsDisabled(Flags.FLAG_DE_HIDL)
public void testStartUser_failsClearsStopUserClient() {
// When a stop user client fails, check that mStopUserClient
// is set to null to prevent the scheduler from getting stuck.
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClientTest.java
index f8b5b04..84c3684 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClientTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClientTest.java
@@ -50,12 +50,17 @@
import android.os.PowerManager;
import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;
+import android.platform.test.annotations.RequiresFlagsDisabled;
+import android.platform.test.annotations.RequiresFlagsEnabled;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.platform.test.flag.junit.SetFlagsRule;
import android.testing.TestableContext;
import androidx.test.filters.SmallTest;
import androidx.test.platform.app.InstrumentationRegistry;
+import com.android.server.biometrics.Flags;
import com.android.server.biometrics.log.BiometricContext;
import com.android.server.biometrics.log.BiometricLogger;
import com.android.server.biometrics.log.OperationContextExt;
@@ -94,6 +99,9 @@
@Rule
public final TestableContext mContext = new TestableContext(
InstrumentationRegistry.getInstrumentation().getTargetContext(), null);
+ @Rule
+ public final CheckFlagsRule mCheckFlagsRule =
+ DeviceFlagsValueProvider.createCheckFlagsRule();
@Mock
private ISession mHal;
@@ -127,6 +135,8 @@
private ArgumentCaptor<OperationContextExt> mOperationContextCaptor;
@Captor
private ArgumentCaptor<Consumer<OperationContext>> mContextInjector;
+ @Captor
+ private ArgumentCaptor<Consumer<OperationContext>> mStartHalConsumerCaptor;
@Rule
public final MockitoRule mockito = MockitoJUnit.rule();
@@ -149,6 +159,7 @@
}
@Test
+ @RequiresFlagsDisabled(Flags.FLAG_DE_HIDL)
public void authWithContext_v2() throws RemoteException {
final FaceAuthenticationClient client = createClient(2);
client.start(mCallback);
@@ -189,6 +200,7 @@
}
@Test
+ @RequiresFlagsDisabled(Flags.FLAG_DE_HIDL)
public void notifyHalWhenContextChanges() throws RemoteException {
final FaceAuthenticationClient client = createClient();
client.start(mCallback);
@@ -211,6 +223,36 @@
}
@Test
+ @RequiresFlagsEnabled(Flags.FLAG_DE_HIDL)
+ public void subscribeContextAndStartHal() throws RemoteException {
+ final FaceAuthenticationClient client = createClient();
+ client.start(mCallback);
+
+ verify(mBiometricContext).subscribe(mOperationContextCaptor.capture(),
+ mStartHalConsumerCaptor.capture(), mContextInjector.capture(), any());
+
+ mStartHalConsumerCaptor.getValue().accept(
+ mOperationContextCaptor.getValue().toAidlContext());
+ final ArgumentCaptor<OperationContext> captor =
+ ArgumentCaptor.forClass(OperationContext.class);
+
+ verify(mHal).authenticateWithContext(eq(OP_ID), captor.capture());
+
+ OperationContext opContext = captor.getValue();
+
+ assertThat(opContext).isSameInstanceAs(
+ mOperationContextCaptor.getValue().toAidlContext());
+
+ mContextInjector.getValue().accept(opContext);
+
+ verify(mHal).onContextChanged(same(opContext));
+
+ client.stopHalOperation();
+
+ verify(mBiometricContext).unsubscribe(same(mOperationContextCaptor.getValue()));
+ }
+
+ @Test
public void cancelsAuthWhenNotInForeground() throws Exception {
final ActivityManager.RunningTaskInfo topTask = new ActivityManager.RunningTaskInfo();
topTask.topActivity = new ComponentName("other", "thing");
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceDetectClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceDetectClientTest.java
index fbf0e13..e626f73 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceDetectClientTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceDetectClientTest.java
@@ -37,11 +37,16 @@
import android.os.RemoteException;
import android.os.Vibrator;
import android.platform.test.annotations.Presubmit;
+import android.platform.test.annotations.RequiresFlagsDisabled;
+import android.platform.test.annotations.RequiresFlagsEnabled;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.testing.TestableContext;
import androidx.test.filters.SmallTest;
import androidx.test.platform.app.InstrumentationRegistry;
+import com.android.server.biometrics.Flags;
import com.android.server.biometrics.log.BiometricContext;
import com.android.server.biometrics.log.BiometricLogger;
import com.android.server.biometrics.log.OperationContextExt;
@@ -71,6 +76,9 @@
@Rule
public final TestableContext mContext = new TestableContext(
InstrumentationRegistry.getInstrumentation().getTargetContext(), null);
+ @Rule
+ public final CheckFlagsRule mCheckFlagsRule =
+ DeviceFlagsValueProvider.createCheckFlagsRule();
@Mock
private ISession mHal;
@@ -91,6 +99,8 @@
@Captor
private ArgumentCaptor<OperationContextExt> mOperationContextCaptor;
@Captor
+ private ArgumentCaptor<Consumer<OperationContext>> mStartHalCaptor;
+ @Captor
private ArgumentCaptor<Consumer<OperationContext>> mContextInjector;
@Rule
@@ -114,6 +124,7 @@
}
@Test
+ @RequiresFlagsDisabled(Flags.FLAG_DE_HIDL)
public void detectWithContext_v2() throws RemoteException {
final FaceDetectClient client = createClient(2);
client.start(mCallback);
@@ -132,6 +143,7 @@
}
@Test
+ @RequiresFlagsDisabled(Flags.FLAG_DE_HIDL)
public void notifyHalWhenContextChanges() throws RemoteException {
final FaceDetectClient client = createClient();
client.start(mCallback);
@@ -154,6 +166,35 @@
}
@Test
+ @RequiresFlagsEnabled(Flags.FLAG_DE_HIDL)
+ public void subscribeContextAndStartHal() throws RemoteException {
+ final FaceDetectClient client = createClient();
+ client.start(mCallback);
+
+ verify(mBiometricContext).subscribe(mOperationContextCaptor.capture(),
+ mStartHalCaptor.capture(), mContextInjector.capture(), any());
+
+ mStartHalCaptor.getValue().accept(mOperationContextCaptor.getValue().toAidlContext());
+ final ArgumentCaptor<OperationContext> captor =
+ ArgumentCaptor.forClass(OperationContext.class);
+
+ verify(mHal).detectInteractionWithContext(captor.capture());
+
+ OperationContext opContext = captor.getValue();
+
+ assertThat(opContext).isSameInstanceAs(
+ mOperationContextCaptor.getValue().toAidlContext());
+
+ mContextInjector.getValue().accept(opContext);
+
+ verify(mHal).onContextChanged(same(opContext));
+
+ client.stopHalOperation();
+
+ verify(mBiometricContext).unsubscribe(same(mOperationContextCaptor.getValue()));
+ }
+
+ @Test
public void doesNotPlayHapticOnInteractionDetected() throws Exception {
final FaceDetectClient client = createClient();
client.start(mCallback);
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceEnrollClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceEnrollClientTest.java
index d662620..43ed07a 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceEnrollClientTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceEnrollClientTest.java
@@ -28,17 +28,21 @@
import static org.mockito.Mockito.when;
import android.hardware.biometrics.common.OperationContext;
-import android.hardware.biometrics.face.FaceEnrollOptions;
import android.hardware.biometrics.face.ISession;
import android.hardware.face.Face;
import android.os.IBinder;
import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;
+import android.platform.test.annotations.RequiresFlagsDisabled;
+import android.platform.test.annotations.RequiresFlagsEnabled;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.testing.TestableContext;
import androidx.test.filters.SmallTest;
import androidx.test.platform.app.InstrumentationRegistry;
+import com.android.server.biometrics.Flags;
import com.android.server.biometrics.log.BiometricContext;
import com.android.server.biometrics.log.BiometricLogger;
import com.android.server.biometrics.log.OperationContextExt;
@@ -68,6 +72,9 @@
@Rule
public final TestableContext mContext = new TestableContext(
InstrumentationRegistry.getInstrumentation().getTargetContext(), null);
+ @Rule
+ public final CheckFlagsRule mCheckFlagsRule =
+ DeviceFlagsValueProvider.createCheckFlagsRule();
@Mock
private ISession mHal;
@@ -89,6 +96,8 @@
private ArgumentCaptor<OperationContextExt> mOperationContextCaptor;
@Captor
private ArgumentCaptor<Consumer<OperationContext>> mContextInjector;
+ @Captor
+ private ArgumentCaptor<Consumer<OperationContext>> mStartHalConsumer;
@Rule
public final MockitoRule mockito = MockitoJUnit.rule();
@@ -109,6 +118,7 @@
}
@Test
+ @RequiresFlagsDisabled(Flags.FLAG_DE_HIDL)
public void enrollWithContext_v2() throws RemoteException {
final FaceEnrollClient client = createClient(2);
client.start(mCallback);
@@ -123,6 +133,7 @@
}
@Test
+ @RequiresFlagsDisabled(Flags.FLAG_DE_HIDL)
public void notifyHalWhenContextChanges() throws RemoteException {
final FaceEnrollClient client = createClient(3);
client.start(mCallback);
@@ -145,6 +156,37 @@
}
@Test
+ @RequiresFlagsEnabled(Flags.FLAG_DE_HIDL)
+ public void subscribeContextAndStartHal() throws RemoteException {
+ final FaceEnrollClient client = createClient(3);
+ client.start(mCallback);
+
+ verify(mBiometricContext).subscribe(
+ mOperationContextCaptor.capture(), mStartHalConsumer.capture(),
+ mContextInjector.capture(), any());
+
+ mStartHalConsumer.getValue().accept(mOperationContextCaptor.getValue().toAidlContext());
+ final ArgumentCaptor<OperationContext> captor =
+ ArgumentCaptor.forClass(OperationContext.class);
+
+ verify(mHal).enrollWithContext(any(), anyByte(), any(), any(), captor.capture());
+
+ OperationContext opContext = captor.getValue();
+
+ assertThat(opContext).isSameInstanceAs(
+ mOperationContextCaptor.getValue().toAidlContext());
+
+ mContextInjector.getValue().accept(opContext);
+
+ verify(mHal).onContextChanged(same(opContext));
+
+ client.stopHalOperation();
+
+ verify(mBiometricContext).unsubscribe(same(mOperationContextCaptor.getValue()));
+ }
+
+ @Test
+ @RequiresFlagsDisabled(Flags.FLAG_DE_HIDL)
public void enrollWithFaceOptions() throws RemoteException {
final FaceEnrollClient client = createClient(4);
client.start(mCallback);
@@ -152,6 +194,20 @@
verify(mHal).enrollWithOptions(any());
}
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_DE_HIDL)
+ public void enrollWithFaceOptionsAfterSubscribingContext() throws RemoteException {
+ final FaceEnrollClient client = createClient(4);
+ client.start(mCallback);
+
+ verify(mBiometricContext).subscribe(mOperationContextCaptor.capture(),
+ mStartHalConsumer.capture(), any(), any());
+
+ mStartHalConsumer.getValue().accept(mOperationContextCaptor.getValue().toAidlContext());
+
+ verify(mHal).enrollWithOptions(any());
+ }
+
private FaceEnrollClient createClient() throws RemoteException {
return createClient(200 /* version */);
}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/hidl/Face10Test.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/hidl/Face10Test.java
index 78c1e08..949d6ee 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/hidl/Face10Test.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/hidl/Face10Test.java
@@ -38,11 +38,15 @@
import android.os.Looper;
import android.os.UserManager;
import android.platform.test.annotations.Presubmit;
+import android.platform.test.annotations.RequiresFlagsDisabled;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import com.android.internal.R;
+import com.android.server.biometrics.Flags;
import com.android.server.biometrics.log.BiometricContext;
import com.android.server.biometrics.sensors.AuthenticationStateListeners;
import com.android.server.biometrics.sensors.BiometricScheduler;
@@ -50,6 +54,7 @@
import com.android.server.biometrics.sensors.LockoutResetDispatcher;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -70,6 +75,10 @@
private static final int USER_ID = 20;
private static final float FRR_THRESHOLD = 0.2f;
+ @Rule
+ public final CheckFlagsRule mCheckFlagsRule =
+ DeviceFlagsValueProvider.createCheckFlagsRule();
+
@Mock
private Context mContext;
@Mock
@@ -145,6 +154,7 @@
}
@Test
+ @RequiresFlagsDisabled(Flags.FLAG_DE_HIDL)
public void scheduleGenerateChallenge_cachesResult() {
final IFaceServiceReceiver[] mocks = IntStream.range(0, 3)
.mapToObj(i -> mock(IFaceServiceReceiver.class))
@@ -163,6 +173,7 @@
}
@Test
+ @RequiresFlagsDisabled(Flags.FLAG_DE_HIDL)
public void scheduleRevokeChallenge_waitsUntilEmpty() {
final long challenge = 22;
final IFaceServiceReceiver[] mocks = IntStream.range(0, 3)
@@ -182,6 +193,7 @@
}
@Test
+ @RequiresFlagsDisabled(Flags.FLAG_DE_HIDL)
public void scheduleRevokeChallenge_doesNotWaitForever() {
mFace10.scheduleGenerateChallenge(
SENSOR_ID, USER_ID, mBinder, mock(IFaceServiceReceiver.class), TAG);
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java
index 4ed6f74..f96d9e8 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java
@@ -56,6 +56,7 @@
import android.os.RemoteException;
import android.os.test.TestLooper;
import android.platform.test.annotations.Presubmit;
+import android.platform.test.annotations.RequiresFlagsDisabled;
import android.platform.test.annotations.RequiresFlagsEnabled;
import android.platform.test.flag.junit.CheckFlagsRule;
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
@@ -158,6 +159,9 @@
private ArgumentCaptor<OperationContextExt> mOperationContextCaptor;
@Captor
private ArgumentCaptor<Consumer<OperationContext>> mContextInjector;
+ @Captor
+ private ArgumentCaptor<Consumer<OperationContext>> mStartHalConsumerCaptor;
+
private final TestLooper mLooper = new TestLooper();
@Before
@@ -175,12 +179,19 @@
public void authNoContext_v1() throws RemoteException {
final FingerprintAuthenticationClient client = createClient(1);
client.start(mCallback);
+ if (Flags.deHidl()) {
+ verify(mBiometricContext).subscribe(mOperationContextCaptor.capture(),
+ mStartHalConsumerCaptor.capture(), mContextInjector.capture(), any());
+ mStartHalConsumerCaptor.getValue().accept(mOperationContextCaptor
+ .getValue().toAidlContext());
+ }
verify(mHal).authenticate(eq(OP_ID));
verify(mHal, never()).authenticateWithContext(anyLong(), any());
}
@Test
+ @RequiresFlagsDisabled(Flags.FLAG_DE_HIDL)
public void authWithContext_v2() throws RemoteException {
final FingerprintAuthenticationClient client = createClient(2);
client.start(mCallback);
@@ -262,15 +273,24 @@
public void luxProbeWhenAwake() throws RemoteException {
when(mBiometricContext.isAwake()).thenReturn(false);
when(mBiometricContext.isAod()).thenReturn(false);
+
final FingerprintAuthenticationClient client = createClient();
client.start(mCallback);
+ if (Flags.deHidl()) {
+ verify(mBiometricContext).subscribe(mOperationContextCaptor.capture(),
+ mStartHalConsumerCaptor.capture(), mContextInjector.capture(), any());
+ mStartHalConsumerCaptor.getValue().accept(mOperationContextCaptor
+ .getValue().toAidlContext());
+ }
final ArgumentCaptor<OperationContext> captor =
ArgumentCaptor.forClass(OperationContext.class);
verify(mHal).authenticateWithContext(eq(OP_ID), captor.capture());
OperationContext opContext = captor.getValue();
- verify(mBiometricContext).subscribe(
- mOperationContextCaptor.capture(), mContextInjector.capture());
+ if (!Flags.deHidl()) {
+ verify(mBiometricContext).subscribe(
+ mOperationContextCaptor.capture(), mContextInjector.capture());
+ }
assertThat(mOperationContextCaptor.getValue().toAidlContext())
.isSameInstanceAs(opContext);
@@ -305,6 +325,12 @@
when(mBiometricContext.isAod()).thenReturn(false);
final FingerprintAuthenticationClient client = createClient();
client.start(mCallback);
+ if (Flags.deHidl()) {
+ verify(mBiometricContext).subscribe(mOperationContextCaptor.capture(),
+ mStartHalConsumerCaptor.capture(), mContextInjector.capture(), any());
+ mStartHalConsumerCaptor.getValue().accept(mOperationContextCaptor
+ .getValue().toAidlContext());
+ }
verify(mLuxProbe, isAwake ? times(1) : never()).enable();
}
@@ -315,13 +341,21 @@
when(mBiometricContext.isAod()).thenReturn(true);
final FingerprintAuthenticationClient client = createClient();
client.start(mCallback);
+ if (Flags.deHidl()) {
+ verify(mBiometricContext).subscribe(mOperationContextCaptor.capture(),
+ mStartHalConsumerCaptor.capture(), mContextInjector.capture(), any());
+ mStartHalConsumerCaptor.getValue().accept(mOperationContextCaptor
+ .getValue().toAidlContext());
+ }
final ArgumentCaptor<OperationContext> captor =
ArgumentCaptor.forClass(OperationContext.class);
verify(mHal).authenticateWithContext(eq(OP_ID), captor.capture());
OperationContext opContext = captor.getValue();
- verify(mBiometricContext).subscribe(
- mOperationContextCaptor.capture(), mContextInjector.capture());
+ if (!Flags.deHidl()) {
+ verify(mBiometricContext).subscribe(
+ mOperationContextCaptor.capture(), mContextInjector.capture());
+ }
assertThat(opContext).isSameInstanceAs(
mOperationContextCaptor.getValue().toAidlContext());
@@ -345,6 +379,7 @@
}
@Test
+ @RequiresFlagsDisabled(Flags.FLAG_DE_HIDL)
public void notifyHalWhenContextChanges() throws RemoteException {
final FingerprintAuthenticationClient client = createClient();
client.start(mCallback);
@@ -367,6 +402,36 @@
}
@Test
+ @RequiresFlagsEnabled(Flags.FLAG_DE_HIDL)
+ public void subscribeContextAndStartHal() throws RemoteException {
+ final FingerprintAuthenticationClient client = createClient();
+ client.start(mCallback);
+
+ verify(mBiometricContext).subscribe(mOperationContextCaptor.capture(),
+ mStartHalConsumerCaptor.capture(), mContextInjector.capture(), any());
+
+ mStartHalConsumerCaptor.getValue().accept(mOperationContextCaptor
+ .getValue().toAidlContext());
+ final ArgumentCaptor<OperationContext> captor =
+ ArgumentCaptor.forClass(OperationContext.class);
+
+ verify(mHal).authenticateWithContext(eq(OP_ID), captor.capture());
+
+ OperationContext opContext = captor.getValue();
+
+ assertThat(opContext).isSameInstanceAs(
+ mOperationContextCaptor.getValue().toAidlContext());
+
+ mContextInjector.getValue().accept(opContext);
+
+ verify(mHal).onContextChanged(same(opContext));
+
+ client.stopHalOperation();
+
+ verify(mBiometricContext).unsubscribe(same(mOperationContextCaptor.getValue()));
+ }
+
+ @Test
public void showHideOverlay_cancel() throws RemoteException {
showHideOverlay(c -> c.cancel());
}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClientTest.java
index a467c84..9edb8dd 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClientTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClientTest.java
@@ -35,11 +35,16 @@
import android.os.IBinder;
import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;
+import android.platform.test.annotations.RequiresFlagsDisabled;
+import android.platform.test.annotations.RequiresFlagsEnabled;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.testing.TestableContext;
import androidx.test.filters.SmallTest;
import androidx.test.platform.app.InstrumentationRegistry;
+import com.android.server.biometrics.Flags;
import com.android.server.biometrics.log.BiometricContext;
import com.android.server.biometrics.log.BiometricLogger;
import com.android.server.biometrics.log.OperationContextExt;
@@ -67,6 +72,9 @@
@Rule
public final TestableContext mContext = new TestableContext(
InstrumentationRegistry.getInstrumentation().getTargetContext(), null);
+ @Rule
+ public final CheckFlagsRule mCheckFlagsRule =
+ DeviceFlagsValueProvider.createCheckFlagsRule();
@Mock
private ISession mHal;
@@ -88,6 +96,8 @@
private ArgumentCaptor<OperationContextExt> mOperationContextCaptor;
@Captor
private ArgumentCaptor<Consumer<OperationContext>> mContextInjector;
+ @Captor
+ private ArgumentCaptor<Consumer<OperationContext>> mStartHalConsumerCaptor;
@Rule
public final MockitoRule mockito = MockitoJUnit.rule();
@@ -109,6 +119,7 @@
}
@Test
+ @RequiresFlagsDisabled(Flags.FLAG_DE_HIDL)
public void detectNoContext_v2() throws RemoteException {
final FingerprintDetectClient client = createClient(2);
@@ -127,6 +138,7 @@
}
@Test
+ @RequiresFlagsDisabled(Flags.FLAG_DE_HIDL)
public void notifyHalWhenContextChanges() throws RemoteException {
final FingerprintDetectClient client = createClient();
client.start(mCallback);
@@ -149,6 +161,31 @@
}
@Test
+ @RequiresFlagsEnabled(Flags.FLAG_DE_HIDL)
+ public void subscribeContextAndStartHal() throws RemoteException {
+ final FingerprintDetectClient client = createClient();
+ client.start(mCallback);
+
+ verify(mBiometricContext).subscribe(mOperationContextCaptor.capture(),
+ mStartHalConsumerCaptor.capture(), mContextInjector.capture(), any());
+
+ mStartHalConsumerCaptor.getValue().accept(
+ mOperationContextCaptor.getValue().toAidlContext());
+ final ArgumentCaptor<OperationContext> captor =
+ ArgumentCaptor.forClass(OperationContext.class);
+ verify(mHal).detectInteractionWithContext(captor.capture());
+ OperationContext opContext = captor.getValue();
+
+ assertThat(opContext).isSameInstanceAs(
+ mOperationContextCaptor.getValue().toAidlContext());
+ mContextInjector.getValue().accept(opContext);
+ verify(mHal).onContextChanged(same(opContext));
+
+ client.stopHalOperation();
+ verify(mBiometricContext).unsubscribe(same(mOperationContextCaptor.getValue()));
+ }
+
+ @Test
public void testWhenListenerIsNull() {
final AidlSession aidl = new AidlSession(0, mHal, USER_ID, mAidlResponseHandler);
final FingerprintDetectClient client = new FingerprintDetectClient(mContext, () -> aidl,
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java
index e7d4a2e..951c9393 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClientTest.java
@@ -40,12 +40,17 @@
import android.os.IBinder;
import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;
+import android.platform.test.annotations.RequiresFlagsDisabled;
+import android.platform.test.annotations.RequiresFlagsEnabled;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.platform.test.flag.junit.SetFlagsRule;
import android.testing.TestableContext;
import androidx.test.filters.SmallTest;
import androidx.test.platform.app.InstrumentationRegistry;
+import com.android.server.biometrics.Flags;
import com.android.server.biometrics.log.BiometricContext;
import com.android.server.biometrics.log.BiometricLogger;
import com.android.server.biometrics.log.CallbackWithProbe;
@@ -73,6 +78,9 @@
public class FingerprintEnrollClientTest {
@Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+ @Rule
+ public final CheckFlagsRule mCheckFlagsRule =
+ DeviceFlagsValueProvider.createCheckFlagsRule();
private static final byte[] HAT = new byte[69];
private static final int USER_ID = 8;
@@ -117,6 +125,8 @@
private ArgumentCaptor<OperationContextExt> mOperationContextCaptor;
@Captor
private ArgumentCaptor<Consumer<OperationContext>> mContextInjector;
+ @Captor
+ private ArgumentCaptor<Consumer<OperationContext>> mStartHalConsumerCaptor;
@Rule
public final MockitoRule mockito = MockitoJUnit.rule();
@@ -140,6 +150,7 @@
}
@Test
+ @RequiresFlagsDisabled(Flags.FLAG_DE_HIDL)
public void enrollWithContext_v2() throws RemoteException {
final FingerprintEnrollClient client = createClient(2);
@@ -236,6 +247,7 @@
}
@Test
+ @RequiresFlagsDisabled(Flags.FLAG_DE_HIDL)
public void notifyHalWhenContextChanges() throws RemoteException {
final FingerprintEnrollClient client = createClient();
client.start(mCallback);
@@ -257,6 +269,30 @@
}
@Test
+ @RequiresFlagsEnabled(Flags.FLAG_DE_HIDL)
+ public void subscribeContextAndStartHal() throws RemoteException {
+ final FingerprintEnrollClient client = createClient();
+ client.start(mCallback);
+
+ verify(mBiometricContext).subscribe(mOperationContextCaptor.capture(),
+ mStartHalConsumerCaptor.capture(), mContextInjector.capture(), any());
+
+ mStartHalConsumerCaptor.getValue().accept(
+ mOperationContextCaptor.getValue().toAidlContext());
+ final ArgumentCaptor<OperationContext> captor =
+ ArgumentCaptor.forClass(OperationContext.class);
+ verify(mHal).enrollWithContext(any(), captor.capture());
+ OperationContext opContext = captor.getValue();
+
+ mContextInjector.getValue().accept(
+ mOperationContextCaptor.getValue().toAidlContext());
+ verify(mHal).onContextChanged(same(opContext));
+
+ client.stopHalOperation();
+ verify(mBiometricContext).unsubscribe(same(mOperationContextCaptor.getValue()));
+ }
+
+ @Test
public void showHideOverlay_cancel() throws RemoteException {
showHideOverlay(c -> c.cancel());
}
diff --git a/services/tests/servicestests/src/com/android/server/credentials/CredentialManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/credentials/CredentialManagerServiceTest.java
index d850c73..57f3cc0 100644
--- a/services/tests/servicestests/src/com/android/server/credentials/CredentialManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/credentials/CredentialManagerServiceTest.java
@@ -22,6 +22,7 @@
import android.os.UserHandle;
import android.provider.Settings;
+import androidx.annotation.NonNull;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -40,10 +41,12 @@
public final class CredentialManagerServiceTest {
Context mContext = null;
+ MockSettingsWrapper mSettingsWrapper = null;
@Before
public void setUp() throws CertificateException {
mContext = ApplicationProvider.getApplicationContext();
+ mSettingsWrapper = new MockSettingsWrapper(mContext);
}
@Test
@@ -81,7 +84,8 @@
Settings.Secure.CREDENTIAL_SERVICE_PRIMARY,
"com.example.test/com.example.test.TestActivity");
- CredentialManagerService.updateProvidersWhenPackageRemoved(mContext, "com.example.test");
+ CredentialManagerService.updateProvidersWhenPackageRemoved(
+ mSettingsWrapper, "com.example.test");
assertThat(getSettingsKey(Settings.Secure.AUTOFILL_SERVICE)).isEqualTo("");
assertThat(getSettingsKey(Settings.Secure.CREDENTIAL_SERVICE))
@@ -101,7 +105,8 @@
setSettingsKey(Settings.Secure.CREDENTIAL_SERVICE, testCredentialValue);
setSettingsKey(Settings.Secure.CREDENTIAL_SERVICE_PRIMARY, testCredentialPrimaryValue);
- CredentialManagerService.updateProvidersWhenPackageRemoved(mContext, "com.example.test3");
+ CredentialManagerService.updateProvidersWhenPackageRemoved(
+ mSettingsWrapper, "com.example.test3");
// Since the provider removed was not a primary provider then we should do nothing.
assertThat(getSettingsKey(Settings.Secure.AUTOFILL_SERVICE))
@@ -125,7 +130,8 @@
Settings.Secure.CREDENTIAL_SERVICE_PRIMARY,
"com.example.test/com.example.test.TestActivity");
- CredentialManagerService.updateProvidersWhenPackageRemoved(mContext, "com.example.test");
+ CredentialManagerService.updateProvidersWhenPackageRemoved(
+ mSettingsWrapper, "com.example.test");
assertThat(getSettingsKey(Settings.Secure.AUTOFILL_SERVICE)).isEqualTo("");
assertThat(getSettingsKey(Settings.Secure.CREDENTIAL_SERVICE))
@@ -144,7 +150,8 @@
setSettingsKey(Settings.Secure.CREDENTIAL_SERVICE, testCredentialValue);
setSettingsKey(Settings.Secure.CREDENTIAL_SERVICE_PRIMARY, testCredentialPrimaryValue);
- CredentialManagerService.updateProvidersWhenPackageRemoved(mContext, "com.example.test3");
+ CredentialManagerService.updateProvidersWhenPackageRemoved(
+ mSettingsWrapper, "com.example.test3");
// Since the provider removed was not a primary provider then we should do nothing.
assertCredentialPropertyEquals(
@@ -176,12 +183,36 @@
assertThat(actualValueSet).isEqualTo(newValueSet);
}
- private void setSettingsKey(String key, String value) {
- assertThat(Settings.Secure.putString(mContext.getContentResolver(), key, value)).isTrue();
+ private void setSettingsKey(String name, String value) {
+ assertThat(
+ mSettingsWrapper.putStringForUser(
+ name, value, UserHandle.myUserId(), true))
+ .isTrue();
}
- private String getSettingsKey(String key) {
- return Settings.Secure.getStringForUser(
- mContext.getContentResolver(), key, UserHandle.myUserId());
+ private String getSettingsKey(String name) {
+ return mSettingsWrapper.getStringForUser(name, UserHandle.myUserId());
+ }
+
+ private static final class MockSettingsWrapper
+ extends CredentialManagerService.SettingsWrapper {
+
+ MockSettingsWrapper(@NonNull Context context) {
+ super(context);
+ }
+
+ /** Updates the string value of a system setting */
+ @Override
+ public boolean putStringForUser(
+ String name,
+ String value,
+ int userHandle,
+ boolean overrideableByRestore) {
+ // This will ensure that when the settings putStringForUser method is called by
+ // CredentialManagerService that the overrideableByRestore bit is true.
+ assertThat(overrideableByRestore).isTrue();
+
+ return Settings.Secure.putStringForUser(getContentResolver(), name, value, userHandle);
+ }
}
}
diff --git a/services/tests/servicestests/src/com/android/server/credentials/ProviderRegistryGetSessionTest.java b/services/tests/servicestests/src/com/android/server/credentials/ProviderRegistryGetSessionTest.java
index 6bc0fbf..0f3f27a 100644
--- a/services/tests/servicestests/src/com/android/server/credentials/ProviderRegistryGetSessionTest.java
+++ b/services/tests/servicestests/src/com/android/server/credentials/ProviderRegistryGetSessionTest.java
@@ -39,8 +39,8 @@
import android.credentials.CredentialOption;
import android.credentials.GetCredentialException;
import android.credentials.GetCredentialResponse;
-import android.credentials.ui.GetCredentialProviderData;
-import android.credentials.ui.ProviderPendingIntentResponse;
+import android.credentials.selection.GetCredentialProviderData;
+import android.credentials.selection.ProviderPendingIntentResponse;
import android.net.Uri;
import android.os.Bundle;
import android.service.credentials.CallingAppInfo;
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
index 6207349..1bd6e29 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
@@ -659,6 +659,64 @@
mTestLooper.dispatchAll();
assertThat(mActiveMediaSessionsPaused).isFalse();
}
+ @Test
+ public void handleRoutingInformation_physicalAddressOfSender_Tv_activeSourceChange() {
+ mHdmiCecLocalDevicePlayback.mService.getHdmiCecConfig().setStringValue(
+ HdmiControlManager.CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST,
+ HdmiControlManager.POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST_STANDBY_NOW);
+ mHdmiCecLocalDevicePlayback.setActiveSource(mPlaybackLogicalAddress,
+ mPlaybackPhysicalAddress, "HdmiCecLocalDevicePlaybackTest");
+ mPowerManager.setInteractive(true);
+ // Physical address reported in this message is the same as message sender's (TV) physical
+ // address.
+ HdmiCecMessage message =
+ HdmiCecMessageBuilder.buildRoutingInformation(Constants.ADDR_TV, 0x0000);
+
+ assertThat(mHdmiCecLocalDevicePlayback.handleRoutingInformation(message))
+ .isEqualTo(Constants.HANDLED);
+ assertThat(mHdmiCecLocalDevicePlayback.isActiveSource()).isFalse();
+ assertThat(mHdmiCecLocalDevicePlayback.getActiveSource().physicalAddress).isEqualTo(
+ 0x0000);
+ // Active source's logical address is invalidated.
+ // See {@link HdmiCecLocalDevicePlayback#handleRoutingChangeAndInformation}.
+ assertThat(mHdmiCecLocalDevicePlayback.getActiveSource().logicalAddress).isEqualTo(
+ ADDR_INVALID);
+ assertThat(mPowerManager.isInteractive()).isFalse();
+ }
+
+ @Test
+ public void handleRoutingInformation_physicalAddressOfSender_notTv_noActiveSourceChange() {
+ mHdmiCecLocalDevicePlayback.mService.getHdmiCecConfig().setStringValue(
+ HdmiControlManager.CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST,
+ HdmiControlManager.POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST_STANDBY_NOW);
+ mHdmiCecLocalDevicePlayback.setActiveSource(mPlaybackLogicalAddress,
+ mPlaybackPhysicalAddress, "HdmiCecLocalDevicePlaybackTest");
+ // Add a device to the network and assert that this device is included in the list of
+ // devices.
+ HdmiDeviceInfo infoPlayback = HdmiDeviceInfo.cecDeviceBuilder()
+ .setLogicalAddress(Constants.ADDR_PLAYBACK_3)
+ .setPhysicalAddress(0x1000)
+ .setPortId(PORT_1)
+ .setDeviceType(HdmiDeviceInfo.DEVICE_PLAYBACK)
+ .setVendorId(0x1000)
+ .setDisplayName("Playback 3")
+ .build();
+ mHdmiControlService.getHdmiCecNetwork().addCecDevice(infoPlayback);
+ mPowerManager.setInteractive(true);
+ // Physical address reported in this message is the same as message sender's (Playback_3)
+ // physical address.
+ HdmiCecMessage message =
+ HdmiCecMessageBuilder.buildRoutingInformation(Constants.ADDR_PLAYBACK_3, 0x1000);
+
+ assertThat(mHdmiCecLocalDevicePlayback.handleRoutingInformation(message))
+ .isEqualTo(Constants.HANDLED);
+ assertThat(mHdmiCecLocalDevicePlayback.isActiveSource()).isTrue();
+ assertThat(mHdmiCecLocalDevicePlayback.getActiveSource().physicalAddress).isEqualTo(
+ mPlaybackPhysicalAddress);
+ assertThat(mHdmiCecLocalDevicePlayback.getActiveSource().logicalAddress).isEqualTo(
+ mPlaybackLogicalAddress);
+ assertThat(mPowerManager.isInteractive()).isTrue();
+ }
@Test
public void handleSetStreamPath() {
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 5e38010..67ae998 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
@@ -170,6 +170,11 @@
}
@Override
+ boolean isPowerOnOrTransient() {
+ return true;
+ }
+
+ @Override
void invokeDeviceEventListeners(HdmiDeviceInfo device, int status) {
mDeviceEventListeners.add(new DeviceEventListener(device, status));
}
@@ -1839,4 +1844,38 @@
assertThat(mNativeWrapper.getResultMessages()).doesNotContain(activeSourceFromTv);
}
+
+ @Test
+ public void handleStandby_fromActiveSource_standby() {
+ mPowerManager.setInteractive(true);
+ mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
+ mHdmiControlService.setActiveSource(ADDR_PLAYBACK_1, 0x1000,
+ "HdmiCecLocalDeviceTvTest");
+ mTestLooper.dispatchAll();
+
+ HdmiCecMessage standbyMessage = HdmiCecMessageBuilder.buildStandby(ADDR_PLAYBACK_1,
+ ADDR_TV);
+ assertThat(mHdmiCecLocalDeviceTv.dispatchMessage(standbyMessage))
+ .isEqualTo(Constants.HANDLED);
+ mTestLooper.dispatchAll();
+
+ assertThat(mPowerManager.isInteractive()).isFalse();
+ }
+
+ @Test
+ public void handleStandby_fromNonActiveSource_noStandby() {
+ mPowerManager.setInteractive(true);
+ mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
+ mHdmiControlService.setActiveSource(ADDR_PLAYBACK_2, 0x2000,
+ "HdmiCecLocalDeviceTvTest");
+ mTestLooper.dispatchAll();
+
+ HdmiCecMessage standbyMessage = HdmiCecMessageBuilder.buildStandby(ADDR_PLAYBACK_1,
+ ADDR_TV);
+ assertThat(mHdmiCecLocalDeviceTv.dispatchMessage(standbyMessage))
+ .isEqualTo(Constants.HANDLED);
+ mTestLooper.dispatchAll();
+
+ assertThat(mPowerManager.isInteractive()).isTrue();
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionManagerServiceTest.java
index 097cc51..abd3abe 100644
--- a/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionManagerServiceTest.java
@@ -49,6 +49,7 @@
import static org.testng.Assert.assertThrows;
import android.app.ActivityManagerInternal;
+import android.app.ActivityOptions.LaunchCookie;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.pm.ApplicationInfo;
@@ -784,7 +785,7 @@
@RecordContent int recordedContent)
throws NameNotFoundException {
MediaProjectionManagerService.MediaProjection projection = startProjectionPreconditions();
- projection.setLaunchCookie(mock(IBinder.class));
+ projection.setLaunchCookie(new LaunchCookie());
projection.start(mIMediaProjectionCallback);
projection.notifyVirtualDisplayCreated(10);
// Waiting for user to review consent.
@@ -825,7 +826,7 @@
public void testSetUserReviewGrantedConsentResult_displayMirroring_noPriorSession()
throws NameNotFoundException {
MediaProjectionManagerService.MediaProjection projection = startProjectionPreconditions();
- projection.setLaunchCookie(mock(IBinder.class));
+ projection.setLaunchCookie(new LaunchCookie());
projection.start(mIMediaProjectionCallback);
// Skip setting the prior session details.
@@ -844,7 +845,7 @@
public void testSetUserReviewGrantedConsentResult_displayMirroring_sessionNotWaiting()
throws NameNotFoundException {
MediaProjectionManagerService.MediaProjection projection = startProjectionPreconditions();
- projection.setLaunchCookie(mock(IBinder.class));
+ projection.setLaunchCookie(new LaunchCookie());
projection.start(mIMediaProjectionCallback);
// Session is not waiting for user's consent.
doReturn(true).when(mWindowManagerInternal).setContentRecordingSession(
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserPropertiesTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserPropertiesTest.java
index d7ed7c2..8d8dc9c 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserPropertiesTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserPropertiesTest.java
@@ -23,6 +23,7 @@
import android.content.pm.UserProperties;
import android.os.Parcel;
import android.platform.test.annotations.Presubmit;
+import android.platform.test.flag.junit.SetFlagsRule;
import android.util.Xml;
import androidx.test.filters.MediumTest;
@@ -31,6 +32,7 @@
import com.android.modules.utils.TypedXmlPullParser;
import com.android.modules.utils.TypedXmlSerializer;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -52,10 +54,13 @@
@RunWith(AndroidJUnit4.class)
@MediumTest
public class UserManagerServiceUserPropertiesTest {
+ @Rule
+ public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
/** Test that UserProperties can properly read the xml information that it writes. */
@Test
public void testWriteReadXml() throws Exception {
+ mSetFlagsRule.enableFlags(android.multiuser.Flags.FLAG_SUPPORT_HIDING_PROFILES);
final UserProperties defaultProps = new UserProperties.Builder()
.setShowInLauncher(21)
.setStartWithParent(false)
@@ -73,6 +78,7 @@
.setDeleteAppWithParent(false)
.setAlwaysVisible(false)
.setCrossProfileContentSharingStrategy(0)
+ .setProfileApiVisibility(34)
.build();
final UserProperties actualProps = new UserProperties(defaultProps);
actualProps.setShowInLauncher(14);
@@ -90,6 +96,7 @@
actualProps.setDeleteAppWithParent(true);
actualProps.setAlwaysVisible(true);
actualProps.setCrossProfileContentSharingStrategy(1);
+ actualProps.setProfileApiVisibility(36);
// Write the properties to xml.
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
@@ -114,6 +121,7 @@
/** Tests parcelling an object in which all properties are present. */
@Test
public void testParcelUnparcel() throws Exception {
+ mSetFlagsRule.enableFlags(android.multiuser.Flags.FLAG_SUPPORT_HIDING_PROFILES);
final UserProperties originalProps = new UserProperties.Builder()
.setShowInLauncher(2145)
.build();
@@ -124,6 +132,7 @@
/** Tests copying a UserProperties object varying permissions. */
@Test
public void testCopyLacksPermissions() throws Exception {
+ mSetFlagsRule.enableFlags(android.multiuser.Flags.FLAG_SUPPORT_HIDING_PROFILES);
final UserProperties defaultProps = new UserProperties.Builder()
.setShowInLauncher(2145)
.setStartWithParent(true)
@@ -134,6 +143,7 @@
.setAuthAlwaysRequiredToDisableQuietMode(false)
.setAllowStoppingUserWithDelayedLocking(false)
.setAlwaysVisible(true)
+ .setProfileApiVisibility(110)
.build();
final UserProperties orig = new UserProperties(defaultProps);
orig.setShowInLauncher(2841);
@@ -209,6 +219,8 @@
copy::isCredentialShareableWithParent, true);
assertEqualGetterOrThrows(orig::getCrossProfileContentSharingStrategy,
copy::getCrossProfileContentSharingStrategy, true);
+ assertEqualGetterOrThrows(orig::getProfileApiVisibility, copy::getProfileApiVisibility,
+ true);
}
/**
@@ -270,5 +282,6 @@
assertThat(expected.getAlwaysVisible()).isEqualTo(actual.getAlwaysVisible());
assertThat(expected.getCrossProfileContentSharingStrategy())
.isEqualTo(actual.getCrossProfileContentSharingStrategy());
+ assertThat(expected.getProfileApiVisibility()).isEqualTo(actual.getProfileApiVisibility());
}
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserTypeTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserTypeTest.java
index 7083706..1ee604e 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserTypeTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserTypeTest.java
@@ -41,6 +41,7 @@
import android.os.Bundle;
import android.os.UserManager;
import android.platform.test.annotations.Presubmit;
+import android.platform.test.flag.junit.SetFlagsRule;
import android.util.ArrayMap;
import androidx.test.InstrumentationRegistry;
@@ -50,6 +51,7 @@
import com.android.frameworks.servicestests.R;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -71,9 +73,11 @@
public void setup() {
mResources = InstrumentationRegistry.getTargetContext().getResources();
}
-
+ @Rule
+ public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
@Test
public void testUserTypeBuilder_createUserType() {
+ mSetFlagsRule.enableFlags(android.multiuser.Flags.FLAG_SUPPORT_HIDING_PROFILES);
final Bundle restrictions = makeRestrictionsBundle("r1", "r2");
final Bundle systemSettings = makeSettingsBundle("s1", "s2");
final Bundle secureSettings = makeSettingsBundle("secure_s1", "secure_s2");
@@ -97,7 +101,8 @@
.setInheritDevicePolicy(340)
.setDeleteAppWithParent(true)
.setAlwaysVisible(true)
- .setCrossProfileContentSharingStrategy(1);
+ .setCrossProfileContentSharingStrategy(1)
+ .setProfileApiVisibility(34);
final UserTypeDetails type = new UserTypeDetails.Builder()
.setName("a.name")
@@ -180,6 +185,7 @@
assertTrue(type.getDefaultUserPropertiesReference().getAlwaysVisible());
assertEquals(1, type.getDefaultUserPropertiesReference()
.getCrossProfileContentSharingStrategy());
+ assertEquals(34, type.getDefaultUserPropertiesReference().getProfileApiVisibility());
assertEquals(23, type.getBadgeLabel(0));
assertEquals(24, type.getBadgeLabel(1));
@@ -199,6 +205,7 @@
@Test
public void testUserTypeBuilder_defaults() {
+ mSetFlagsRule.enableFlags(android.multiuser.Flags.FLAG_SUPPORT_HIDING_PROFILES);
UserTypeDetails type = new UserTypeDetails.Builder()
.setName("name") // Required (no default allowed)
.setBaseType(FLAG_FULL) // Required (no default allowed)
@@ -238,6 +245,8 @@
props.getShowInQuietMode());
assertEquals(UserProperties.CROSS_PROFILE_CONTENT_SHARING_NO_DELEGATION,
props.getCrossProfileContentSharingStrategy());
+ assertEquals(UserProperties.PROFILE_API_VISIBILITY_VISIBLE,
+ props.getProfileApiVisibility());
assertFalse(type.hasBadge());
}
@@ -310,6 +319,7 @@
/** Tests {@link UserTypeFactory#customizeBuilders} for a reasonable xml file. */
@Test
public void testUserTypeFactoryCustomize_profile() throws Exception {
+ mSetFlagsRule.enableFlags(android.multiuser.Flags.FLAG_SUPPORT_HIDING_PROFILES);
final String userTypeAosp1 = "android.test.1"; // Profile user that is not customized
final String userTypeAosp2 = "android.test.2"; // Profile user that is customized
final String userTypeOem1 = "custom.test.1"; // Custom-defined profile
@@ -332,7 +342,8 @@
.setShowInQuietMode(24)
.setDeleteAppWithParent(true)
.setAlwaysVisible(false)
- .setCrossProfileContentSharingStrategy(1);
+ .setCrossProfileContentSharingStrategy(1)
+ .setProfileApiVisibility(36);
final ArrayMap<String, UserTypeDetails.Builder> builders = new ArrayMap<>();
builders.put(userTypeAosp1, new UserTypeDetails.Builder()
@@ -383,6 +394,7 @@
assertFalse(aospType.getDefaultUserPropertiesReference().getAlwaysVisible());
assertEquals(1, aospType.getDefaultUserPropertiesReference()
.getCrossProfileContentSharingStrategy());
+ assertEquals(36, aospType.getDefaultUserPropertiesReference().getProfileApiVisibility());
// userTypeAosp2 should be modified.
aospType = builders.get(userTypeAosp2).createUserTypeDetails();
@@ -439,6 +451,7 @@
assertTrue(aospType.getDefaultUserPropertiesReference().getAlwaysVisible());
assertEquals(0, aospType.getDefaultUserPropertiesReference()
.getCrossProfileContentSharingStrategy());
+ assertEquals(36, aospType.getDefaultUserPropertiesReference().getProfileApiVisibility());
// userTypeOem1 should be created.
UserTypeDetails.Builder customType = builders.get(userTypeOem1);
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
index 06be456..db561c4 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
@@ -39,6 +39,7 @@
import android.os.UserManager;
import android.platform.test.annotations.Postsubmit;
import android.platform.test.annotations.RequiresFlagsEnabled;
+import android.platform.test.flag.junit.SetFlagsRule;
import android.provider.Settings;
import android.test.suitebuilder.annotation.LargeTest;
import android.test.suitebuilder.annotation.MediumTest;
@@ -55,6 +56,7 @@
import org.junit.After;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -97,6 +99,8 @@
private UserSwitchWaiter mUserSwitchWaiter;
private UserRemovalWaiter mUserRemovalWaiter;
private int mOriginalCurrentUserId;
+ @Rule
+ public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
@Before
public void setUp() throws Exception {
@@ -168,6 +172,7 @@
@Test
public void testCloneUser() throws Exception {
+ mSetFlagsRule.enableFlags(android.multiuser.Flags.FLAG_SUPPORT_HIDING_PROFILES);
assumeCloneEnabled();
UserHandle mainUser = mUserManager.getMainUser();
assumeTrue("Main user is null", mainUser != null);
@@ -224,6 +229,7 @@
.isEqualTo(cloneUserProperties.getCrossProfileContentSharingStrategy());
assertThrows(SecurityException.class, cloneUserProperties::getDeleteAppWithParent);
assertThrows(SecurityException.class, cloneUserProperties::getAlwaysVisible);
+ assertThrows(SecurityException.class, cloneUserProperties::getProfileApiVisibility);
compareDrawables(mUserManager.getUserBadge(),
Resources.getSystem().getDrawable(userTypeDetails.getBadgePlain()));
@@ -305,6 +311,7 @@
@Test
public void testPrivateProfile() throws Exception {
+ mSetFlagsRule.enableFlags(android.multiuser.Flags.FLAG_SUPPORT_HIDING_PROFILES);
UserHandle mainUser = mUserManager.getMainUser();
assumeTrue("Main user is null", mainUser != null);
// Get the default properties for private profile user type.
@@ -346,7 +353,8 @@
assertThrows(SecurityException.class, privateProfileUserProperties::getDeleteAppWithParent);
assertThrows(SecurityException.class,
privateProfileUserProperties::getAllowStoppingUserWithDelayedLocking);
-
+ assertThrows(SecurityException.class,
+ privateProfileUserProperties::getProfileApiVisibility);
compareDrawables(mUserManager.getUserBadge(),
Resources.getSystem().getDrawable(userTypeDetails.getBadgePlain()));
diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingValidationTest.kt b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingValidationTest.kt
index 757abde..e3ee21a 100644
--- a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingValidationTest.kt
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingValidationTest.kt
@@ -436,6 +436,13 @@
validateTagCount("action", 20000, tag)
validateTagCount("category", 40000, tag)
validateTagCount("data", 40000, tag)
+ validateTagCount("uri-relative-filter-group", 100, tag)
+ }
+
+ @Test
+ fun parseUriRelativeFilterGroupTag() {
+ val tag = "uri-relative-filter-group"
+ validateTagCount("data", 100, tag)
}
@Test
@@ -465,6 +472,54 @@
R.styleable.AndroidManifestData_pathAdvancedPattern,
4000
)
+ validateTagAttr(tag, "query", R.styleable.AndroidManifestData_query, 4000)
+ validateTagAttr(
+ tag,
+ "queryPattern",
+ R.styleable.AndroidManifestData_queryPattern,
+ 4000
+ )
+ validateTagAttr(
+ tag,
+ "queryPrefix",
+ R.styleable.AndroidManifestData_queryPrefix,
+ 4000
+ )
+ validateTagAttr(tag,
+ "querySuffix",
+ R.styleable.AndroidManifestData_querySuffix,
+ 4000
+ )
+ validateTagAttr(
+ tag,
+ "queryAdvancedPattern",
+ R.styleable.AndroidManifestData_queryAdvancedPattern,
+ 4000
+ )
+ validateTagAttr(tag, "fragment", R.styleable.AndroidManifestData_query, 4000)
+ validateTagAttr(
+ tag,
+ "fragmentPattern",
+ R.styleable.AndroidManifestData_fragmentPattern,
+ 4000
+ )
+ validateTagAttr(
+ tag,
+ "fragmentPrefix",
+ R.styleable.AndroidManifestData_fragmentPrefix,
+ 4000
+ )
+ validateTagAttr(tag,
+ "fragmentSuffix",
+ R.styleable.AndroidManifestData_fragmentSuffix,
+ 4000
+ )
+ validateTagAttr(
+ tag,
+ "fragmentAdvancedPattern",
+ R.styleable.AndroidManifestData_fragmentAdvancedPattern,
+ 4000
+ )
validateTagAttr(tag, "mimeType", R.styleable.AndroidManifestData_mimeType, 255)
validateTagAttr(tag, "mimeGroup", R.styleable.AndroidManifestData_mimeGroup, 1024)
}
diff --git a/services/tests/servicestests/test-apps/PackageParserApp/Android.bp b/services/tests/servicestests/test-apps/PackageParserApp/Android.bp
index 3e78f9a..131b380 100644
--- a/services/tests/servicestests/test-apps/PackageParserApp/Android.bp
+++ b/services/tests/servicestests/test-apps/PackageParserApp/Android.bp
@@ -102,3 +102,17 @@
resource_dirs: ["res"],
manifest: "AndroidManifestApp6.xml",
}
+
+android_test_helper_app {
+ name: "PackageParserTestApp7",
+ sdk_version: "current",
+ srcs: ["**/*.java"],
+ dex_preopt: {
+ enabled: false,
+ },
+ optimize: {
+ enabled: false,
+ },
+ resource_dirs: ["res"],
+ manifest: "AndroidManifestApp7.xml",
+}
diff --git a/services/tests/servicestests/test-apps/PackageParserApp/AndroidManifestApp7.xml b/services/tests/servicestests/test-apps/PackageParserApp/AndroidManifestApp7.xml
new file mode 100644
index 0000000..cb87a48
--- /dev/null
+++ b/services/tests/servicestests/test-apps/PackageParserApp/AndroidManifestApp7.xml
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.servicestests.apps.packageparserapp" >
+
+ <application>
+ <activity android:name=".TestActivity"
+ android:exported="true" >
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.BROWSABLE" />
+ <data android:scheme="http"
+ android:host="www.example.com" />
+ <uri-relative-filter-group android:allow="false">
+ <data android:pathPrefix="/gizmos" />
+ <data android:queryPattern=".*query=string.*" />
+ <data android:fragment="fragment" />
+ </uri-relative-filter-group>
+ <uri-relative-filter-group>
+ <data android:query="query=string" />
+ <data android:fragmentSuffix="fragment" />
+ </uri-relative-filter-group>
+ <uri-relative-filter-group>
+ <data android:path="/gizmos" />
+ <data android:query=".*query=string.*" />
+ <data android:fragment="fragment" />
+ </uri-relative-filter-group>
+ <uri-relative-filter-group>
+ <data android:pathPrefix="/gizmos" />
+ <data android:queryPrefix=".*query=string.*" />
+ <data android:fragmentPrefix="fragment" />
+ </uri-relative-filter-group>
+ <uri-relative-filter-group>
+ <data android:pathPattern="/gizmos" />
+ <data android:queryPattern=".*query=string.*" />
+ <data android:fragmentPattern="fragment" />
+ </uri-relative-filter-group>
+ <uri-relative-filter-group>
+ <data android:pathAdvancedPattern="/gizmos" />
+ <data android:queryAdvancedPattern=".*query=string.*" />
+ <data android:fragmentAdvancedPattern="fragment" />
+ </uri-relative-filter-group>
+ <uri-relative-filter-group>
+ <data android:pathSuffix="/gizmos" />
+ <data android:querySuffix=".*query=string.*" />
+ <data android:fragmentSuffix="fragment" />
+ </uri-relative-filter-group>
+ </intent-filter>
+ </activity>
+ </application>
+
+</manifest>
\ No newline at end of file
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
index 227265a..87e822c 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
@@ -4762,6 +4762,7 @@
.setShouldDimWallpaper(true)
.setShouldUseNightMode(true)
.build();
+ user1Rule.zenPolicy = new ZenPolicy();
verifyNoMoreInteractions(mDeviceEffectsApplier);
mZenModeHelper.onUserSwitched(1);
@@ -5042,6 +5043,109 @@
}
@Test
+ @EnableFlags(Flags.FLAG_MODES_API)
+ public void removeAndAddAutomaticZenRule_wasActive_isRestoredAsInactive() {
+ // Start with a rule.
+ mZenModeHelper.mConfig.automaticRules.clear();
+ AutomaticZenRule rule = new AutomaticZenRule.Builder("Test", CONDITION_ID)
+ .setConditionId(CONDITION_ID)
+ .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
+ .build();
+ String ruleId = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(), rule,
+ UPDATE_ORIGIN_APP, "add it", CUSTOM_PKG_UID);
+
+ // User customizes it.
+ AutomaticZenRule userUpdate = new AutomaticZenRule.Builder(rule)
+ .setInterruptionFilter(INTERRUPTION_FILTER_ALARMS)
+ .build();
+ mZenModeHelper.updateAutomaticZenRule(ruleId, userUpdate, UPDATE_ORIGIN_USER, "userUpdate",
+ Process.SYSTEM_UID);
+ assertThat(mZenModeHelper.getZenMode()).isEqualTo(ZEN_MODE_OFF);
+
+ // App activates it.
+ mZenModeHelper.setAutomaticZenRuleState(ruleId, CONDITION_TRUE, UPDATE_ORIGIN_APP,
+ CUSTOM_PKG_UID);
+ assertThat(mZenModeHelper.getZenMode()).isEqualTo(ZEN_MODE_ALARMS);
+
+ // App deletes it.
+ mZenModeHelper.removeAutomaticZenRule(ruleId, UPDATE_ORIGIN_APP, "delete it",
+ CUSTOM_PKG_UID);
+ assertThat(mZenModeHelper.mConfig.automaticRules).hasSize(0);
+ assertThat(mZenModeHelper.mConfig.deletedRules).hasSize(1);
+ assertThat(mZenModeHelper.getZenMode()).isEqualTo(ZEN_MODE_OFF);
+
+ // App adds it again.
+ String newRuleId = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(), rule,
+ UPDATE_ORIGIN_APP, "add it again", CUSTOM_PKG_UID);
+
+ // The rule is restored...
+ assertThat(newRuleId).isEqualTo(ruleId);
+ AutomaticZenRule finalRule = mZenModeHelper.getAutomaticZenRule(newRuleId);
+ assertThat(finalRule.getInterruptionFilter()).isEqualTo(INTERRUPTION_FILTER_ALARMS);
+
+ // ... but it is NOT active
+ ZenRule storedRule = mZenModeHelper.mConfig.automaticRules.get(newRuleId);
+ assertThat(storedRule.isAutomaticActive()).isFalse();
+ assertThat(storedRule.isTrueOrUnknown()).isFalse();
+ assertThat(storedRule.condition).isNull();
+ assertThat(mZenModeHelper.getZenMode()).isEqualTo(ZEN_MODE_OFF);
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_MODES_API)
+ public void removeAndAddAutomaticZenRule_wasSnoozed_isRestoredAsInactive() {
+ // Start with a rule.
+ mZenModeHelper.mConfig.automaticRules.clear();
+ AutomaticZenRule rule = new AutomaticZenRule.Builder("Test", CONDITION_ID)
+ .setConditionId(CONDITION_ID)
+ .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
+ .build();
+ String ruleId = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(), rule,
+ UPDATE_ORIGIN_APP, "add it", CUSTOM_PKG_UID);
+
+ // User customizes it.
+ AutomaticZenRule userUpdate = new AutomaticZenRule.Builder(rule)
+ .setInterruptionFilter(INTERRUPTION_FILTER_ALARMS)
+ .build();
+ mZenModeHelper.updateAutomaticZenRule(ruleId, userUpdate, UPDATE_ORIGIN_USER, "userUpdate",
+ Process.SYSTEM_UID);
+ assertThat(mZenModeHelper.getZenMode()).isEqualTo(ZEN_MODE_OFF);
+
+ // App activates it.
+ mZenModeHelper.setAutomaticZenRuleState(ruleId, CONDITION_TRUE, UPDATE_ORIGIN_APP,
+ CUSTOM_PKG_UID);
+ assertThat(mZenModeHelper.getZenMode()).isEqualTo(ZEN_MODE_ALARMS);
+
+ // User snoozes it.
+ mZenModeHelper.setManualZenMode(ZEN_MODE_OFF, null, UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI,
+ "snoozing", "systemui", Process.SYSTEM_UID);
+ assertThat(mZenModeHelper.getZenMode()).isEqualTo(ZEN_MODE_OFF);
+
+ // App deletes it.
+ mZenModeHelper.removeAutomaticZenRule(ruleId, UPDATE_ORIGIN_APP, "delete it",
+ CUSTOM_PKG_UID);
+ assertThat(mZenModeHelper.mConfig.automaticRules).hasSize(0);
+ assertThat(mZenModeHelper.mConfig.deletedRules).hasSize(1);
+
+ // App adds it again.
+ String newRuleId = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(), rule,
+ UPDATE_ORIGIN_APP, "add it again", CUSTOM_PKG_UID);
+
+ // The rule is restored...
+ assertThat(newRuleId).isEqualTo(ruleId);
+ AutomaticZenRule finalRule = mZenModeHelper.getAutomaticZenRule(newRuleId);
+ assertThat(finalRule.getInterruptionFilter()).isEqualTo(INTERRUPTION_FILTER_ALARMS);
+
+ // ... but it is NEITHER active NOR snoozed.
+ ZenRule storedRule = mZenModeHelper.mConfig.automaticRules.get(newRuleId);
+ assertThat(storedRule.isAutomaticActive()).isFalse();
+ assertThat(storedRule.isTrueOrUnknown()).isFalse();
+ assertThat(storedRule.condition).isNull();
+ assertThat(storedRule.snoozing).isFalse();
+ assertThat(mZenModeHelper.getZenMode()).isEqualTo(ZEN_MODE_OFF);
+ }
+
+ @Test
public void testRuleCleanup() throws Exception {
mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
Instant now = Instant.ofEpochMilli(1701796461000L);
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityOptionsTest.java b/services/tests/wmtests/src/com/android/server/wm/ActivityOptionsTest.java
index 6e5baee..37e0818 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityOptionsTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityOptionsTest.java
@@ -46,6 +46,7 @@
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
+import android.os.IRemoteCallback;
import android.platform.test.annotations.Presubmit;
import android.util.Log;
import android.util.Rational;
@@ -63,6 +64,7 @@
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
/**
* Build/Install/Run:
@@ -119,6 +121,29 @@
}
@Test
+ public void testAbortListenerCalled() {
+ AtomicBoolean callbackCalled = new AtomicBoolean(false);
+
+ ActivityOptions options = ActivityOptions.makeBasic();
+ options.setOnAnimationAbortListener(new IRemoteCallback.Stub() {
+ @Override
+ public void sendResult(Bundle data) {
+ callbackCalled.set(true);
+ }
+ });
+
+ // Verify that the callback is called on abort
+ options.abort();
+ assertTrue(callbackCalled.get());
+
+ // Verify that the callback survives saving to bundle
+ ActivityOptions optionsCopy = ActivityOptions.fromBundle(options.toBundle());
+ callbackCalled.set(false);
+ optionsCopy.abort();
+ assertTrue(callbackCalled.get());
+ }
+
+ @Test
public void testTransferLaunchCookie() {
final Binder cookie = new Binder();
final ActivityOptions options = ActivityOptions.makeBasic();
@@ -279,7 +304,9 @@
case "android.activity.pendingIntentCreatorBackgroundActivityStartMode":
// KEY_PENDING_INTENT_CREATOR_BACKGROUND_ACTIVITY_START_MODE
case "android.activity.launchCookie": // KEY_LAUNCH_COOKIE
+ case "android:activity.animAbortListener": // KEY_ANIM_ABORT_LISTENER
// Existing keys
+
break;
default:
unknownKeys.add(key);
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java
index 245b2c5..98ca094 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java
@@ -16,6 +16,8 @@
package com.android.server.wm;
+import static android.Manifest.permission.EMBED_ANY_APP_IN_UNTRUSTED_MODE;
+import static android.Manifest.permission.MANAGE_ACTIVITY_TASKS;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
@@ -24,11 +26,14 @@
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.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
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.mockitoSession;
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;
@@ -65,12 +70,14 @@
import androidx.test.filters.MediumTest;
import com.android.server.pm.pkg.AndroidPackage;
+import com.android.window.flags.Flags;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import org.mockito.MockitoSession;
import java.util.Collections;
import java.util.Set;
@@ -592,6 +599,70 @@
}
@Test
+ public void testIsAllowedToBeEmbeddedInTrustedMode_withManageActivityTasksPermission() {
+ final TaskFragment taskFragment = new TaskFragmentBuilder(mAtm)
+ .setCreateParentTask()
+ .createActivityCount(1)
+ .build();
+ final ActivityRecord activity = taskFragment.getTopMostActivity();
+
+ // Not allow embedding activity if not a trusted host.
+ assertEquals(EMBEDDING_DISALLOWED_UNTRUSTED_HOST,
+ taskFragment.isAllowedToEmbedActivity(activity));
+
+ MockitoSession session =
+ mockitoSession().spyStatic(ActivityTaskManagerService.class).startMocking();
+ try {
+ doReturn(PERMISSION_GRANTED).when(() -> {
+ return ActivityTaskManagerService.checkPermission(
+ eq(MANAGE_ACTIVITY_TASKS), anyInt(), anyInt());
+ });
+ // With the MANAGE_ACTIVITY_TASKS permission, trusted embedding is always allowed.
+ assertTrue(taskFragment.isAllowedToBeEmbeddedInTrustedMode());
+ } finally {
+ session.finishMocking();
+ }
+ }
+
+ @Test
+ public void testIsAllowedToEmbedActivityInUntrustedMode_withUntrustedEmbeddingAnyAppPermission(
+ ) {
+ final TaskFragment taskFragment = new TaskFragmentBuilder(mAtm)
+ .setCreateParentTask()
+ .createActivityCount(1)
+ .build();
+ final ActivityRecord activity = taskFragment.getTopMostActivity();
+
+ // Not allow embedding activity if not a trusted host.
+ assertEquals(EMBEDDING_DISALLOWED_UNTRUSTED_HOST,
+ taskFragment.isAllowedToEmbedActivity(activity));
+
+ MockitoSession session =
+ mockitoSession()
+ .spyStatic(ActivityTaskManagerService.class)
+ .spyStatic(Flags.class)
+ .startMocking();
+ try {
+ doReturn(PERMISSION_GRANTED).when(() -> {
+ return ActivityTaskManagerService.checkPermission(
+ eq(EMBED_ANY_APP_IN_UNTRUSTED_MODE), anyInt(), anyInt());
+ });
+ // With the EMBED_ANY_APP_IN_UNTRUSTED_MODE permission, untrusted embedding is always
+ // allowed, but it doesn't always allow trusted embedding.
+ doReturn(true).when(() -> Flags.untrustedEmbeddingAnyAppPermission());
+ assertTrue(taskFragment.isAllowedToEmbedActivityInUntrustedMode(activity));
+ assertFalse(taskFragment.isAllowedToEmbedActivityInTrustedMode(activity));
+
+ // If the flag is disabled, the permission doesn't have effect.
+ doReturn(false).when(() -> Flags.untrustedEmbeddingAnyAppPermission());
+ assertFalse(taskFragment.isAllowedToEmbedActivityInUntrustedMode(activity));
+ assertFalse(taskFragment.isAllowedToEmbedActivityInTrustedMode(activity));
+ } finally {
+ session.finishMocking();
+ }
+ }
+
+ @Test
public void testIgnoreRequestedOrientationForActivityEmbeddingSplit() {
// Setup two activities in ActivityEmbedding split.
final Task task = createTask(mDisplayContent);
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
index 07cfbf0..16f963f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
@@ -628,6 +628,27 @@
}
@Test
+ public void testLaunchWindowingModeUpdatesExistingTask() {
+ final TestDisplayContent freeformDisplay = createNewDisplayContent(
+ WINDOWING_MODE_FREEFORM);
+
+ mCurrent.mPreferredTaskDisplayArea = freeformDisplay.getDefaultTaskDisplayArea();
+ ActivityRecord activity = createSourceActivity(freeformDisplay);
+ final Task task = activity.getTask();
+ task.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchWindowingMode(WINDOWING_MODE_FREEFORM);
+
+ assertEquals(RESULT_CONTINUE,
+ new CalculateRequestBuilder()
+ .setTask(task)
+ .setOptions(options)
+ .calculate());
+
+ assertEquals(WINDOWING_MODE_FREEFORM, mResult.mWindowingMode);
+ }
+
+ @Test
public void testBoundsInOptionsInfersFreeformWithResizeableActivity() {
final ActivityOptions options = ActivityOptions.makeBasic();
options.setLaunchBounds(new Rect(0, 0, 100, 100));
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTransactionTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTransactionTests.java
index d255271..e9ece5d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTransactionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTransactionTests.java
@@ -16,6 +16,9 @@
package com.android.server.wm;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static org.junit.Assert.assertEquals;
@@ -23,6 +26,7 @@
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.atLeast;
+import static org.mockito.Mockito.times;
import android.content.Intent;
import android.platform.test.annotations.Presubmit;
@@ -35,6 +39,9 @@
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.ArrayList;
+import java.util.List;
+
/**
* Test class for {@link WindowContainerTransaction}.
*
@@ -45,7 +52,6 @@
@Presubmit
@RunWith(WindowTestRunner.class)
public class WindowContainerTransactionTests extends WindowTestsBase {
-
@Test
public void testRemoveTask() {
final Task rootTask = createTask(mDisplayContent);
@@ -72,6 +78,123 @@
verify(mAtm.getLockTaskController(), atLeast(1)).clearLockedTask(rootTask);
}
+ @Test
+ public void testDesktopMode_tasksAreBroughtToFront() {
+ final TestDesktopOrganizer desktopOrganizer = new TestDesktopOrganizer(mAtm);
+ TaskDisplayArea tda = desktopOrganizer.mDefaultTDA;
+ List<ActivityRecord> activityRecords = new ArrayList<>();
+ int numberOfTasks = 4;
+ desktopOrganizer.createFreeformTasksWithActivities(desktopOrganizer,
+ activityRecords, numberOfTasks);
+
+ final Task task = createTask(mDisplayContent);
+ final ActivityRecord activity = createActivityRecord(mDisplayContent, task);
+ task.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+
+ // Bring home to front of the tasks
+ desktopOrganizer.bringHomeToFront();
+
+ // Bring tasks in front of the home
+ WindowContainerTransaction wct = new WindowContainerTransaction();
+ desktopOrganizer.bringDesktopTasksToFront(wct);
+ applyTransaction(wct);
+
+ // Verify tasks are resumed and in correct z-order
+ verify(mRootWindowContainer, times(2)).ensureActivitiesVisible();
+ for (int i = 0; i < numberOfTasks - 1; i++) {
+ assertTrue(tda.mChildren
+ .indexOf(desktopOrganizer.mTasks.get(i).getRootTask())
+ < tda.mChildren.indexOf(desktopOrganizer.mTasks.get(i + 1).getRootTask()));
+ }
+ }
+
+ @Test
+ public void testDesktopMode_moveTaskToDesktop() {
+ final TestDesktopOrganizer desktopOrganizer = new TestDesktopOrganizer(mAtm);
+ TaskDisplayArea tda = desktopOrganizer.mDefaultTDA;
+ List<ActivityRecord> activityRecords = new ArrayList<>();
+ int numberOfTasks = 4;
+ desktopOrganizer.createFreeformTasksWithActivities(desktopOrganizer,
+ activityRecords, numberOfTasks);
+
+ final Task task = createTask(mDisplayContent);
+ final ActivityRecord activity = createActivityRecord(mDisplayContent, task);
+ task.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+
+ // Bring home to front of the tasks
+ desktopOrganizer.bringHomeToFront();
+
+ // Bring tasks in front of the home and newly moved task to on top of them
+ WindowContainerTransaction wct = new WindowContainerTransaction();
+ desktopOrganizer.bringDesktopTasksToFront(wct);
+ desktopOrganizer.addMoveToDesktopChanges(wct, task, true);
+ wct.setBounds(task.getTaskInfo().token, desktopOrganizer.getDefaultDesktopTaskBounds());
+ applyTransaction(wct);
+
+ // Verify tasks are resumed
+ verify(mRootWindowContainer, times(2)).ensureActivitiesVisible();
+
+ // Tasks are in correct z-order
+ for (int i = 0; i < numberOfTasks - 1; i++) {
+ assertTrue(tda.mChildren
+ .indexOf(desktopOrganizer.mTasks.get(i).getRootTask())
+ < tda.mChildren.indexOf(desktopOrganizer.mTasks.get(i + 1).getRootTask()));
+ }
+ // New task is on top of other tasks
+ assertTrue(tda.mChildren
+ .indexOf(desktopOrganizer.mTasks.get(3).getRootTask())
+ < tda.mChildren.indexOf(task));
+
+ // New task is in freeform and has specified bounds
+ assertEquals(WINDOWING_MODE_FREEFORM, task.getWindowingMode());
+ assertEquals(desktopOrganizer.getDefaultDesktopTaskBounds(), task.getBounds());
+ }
+
+
+ @Test
+ public void testDesktopMode_moveTaskToFullscreen() {
+ final TestDesktopOrganizer desktopOrganizer = new TestDesktopOrganizer(mAtm);
+ List<ActivityRecord> activityRecords = new ArrayList<>();
+ int numberOfTasks = 4;
+ desktopOrganizer.createFreeformTasksWithActivities(desktopOrganizer,
+ activityRecords, numberOfTasks);
+
+ Task taskToMove = desktopOrganizer.mTasks.get(numberOfTasks - 1);
+
+ // Bring tasks in front of the home and newly moved task to on top of them
+ WindowContainerTransaction wct = new WindowContainerTransaction();
+ desktopOrganizer.addMoveToFullscreen(wct, taskToMove, false);
+ applyTransaction(wct);
+
+ // New task is in freeform
+ assertEquals(WINDOWING_MODE_FULLSCREEN, taskToMove.getWindowingMode());
+ }
+
+ @Test
+ public void testDesktopMode_moveTaskToFront() {
+ final TestDesktopOrganizer desktopOrganizer = new TestDesktopOrganizer(mAtm);
+ TaskDisplayArea tda = desktopOrganizer.mDefaultTDA;
+ List<ActivityRecord> activityRecords = new ArrayList<>();
+ int numberOfTasks = 5;
+ desktopOrganizer.createFreeformTasksWithActivities(desktopOrganizer,
+ activityRecords, numberOfTasks);
+
+ // Bring task 2 on top of other tasks
+ WindowContainerTransaction wct = new WindowContainerTransaction();
+ wct.reorder(desktopOrganizer.mTasks.get(2).getTaskInfo().token, true /* onTop */);
+ applyTransaction(wct);
+
+ // Tasks are in correct z-order
+ assertTrue(tda.mChildren.indexOf(desktopOrganizer.mTasks.get(0).getRootTask())
+ < tda.mChildren.indexOf(desktopOrganizer.mTasks.get(1).getRootTask()));
+ assertTrue(tda.mChildren.indexOf(desktopOrganizer.mTasks.get(1).getRootTask())
+ < tda.mChildren.indexOf(desktopOrganizer.mTasks.get(3).getRootTask()));
+ assertTrue(tda.mChildren.indexOf(desktopOrganizer.mTasks.get(3).getRootTask())
+ < tda.mChildren.indexOf(desktopOrganizer.mTasks.get(4).getRootTask()));
+ assertTrue(tda.mChildren.indexOf(desktopOrganizer.mTasks.get(4).getRootTask())
+ < tda.mChildren.indexOf(desktopOrganizer.mTasks.get(2).getRootTask()));
+ }
+
private Task createTask(int taskId) {
return new Task.Builder(mAtm)
.setTaskId(taskId)
@@ -87,3 +210,4 @@
}
}
}
+
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 a0bafb6..be83744 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -116,6 +116,7 @@
import android.window.TaskFragmentOrganizer;
import android.window.TransitionInfo;
import android.window.TransitionRequestInfo;
+import android.window.WindowContainerTransaction;
import com.android.internal.policy.AttributeCache;
import com.android.internal.util.ArrayUtils;
@@ -1899,12 +1900,14 @@
final int mDesktopModeDefaultWidthDp = 840;
final int mDesktopModeDefaultHeightDp = 630;
final int mDesktopDensity = 284;
+ final int mOverrideDensity = 285;
final ActivityTaskManagerService mService;
final TaskDisplayArea mDefaultTDA;
List<Task> mTasks;
final DisplayContent mDisplay;
Rect mStableBounds;
+ Task mHomeTask;
TestDesktopOrganizer(ActivityTaskManagerService service, DisplayContent display) {
mService = service;
@@ -1913,8 +1916,8 @@
mService.mTaskOrganizerController.registerTaskOrganizer(this);
mTasks = new ArrayList<>();
mStableBounds = display.getBounds();
+ mHomeTask = mDefaultTDA.getRootHomeTask();
}
-
TestDesktopOrganizer(ActivityTaskManagerService service) {
this(service, service.mTaskSupervisor.mRootWindowContainer.getDefaultDisplay());
}
@@ -1929,8 +1932,10 @@
}
public Rect getDefaultDesktopTaskBounds() {
- int width = (int) (mDesktopModeDefaultWidthDp * mDesktopDensity + 0.5f);
- int height = (int) (mDesktopModeDefaultHeightDp * mDesktopDensity + 0.5f);
+ int width = (int) (mDesktopModeDefaultWidthDp
+ * (mOverrideDensity / mDesktopDensity) + 0.5f);
+ int height = (int) (mDesktopModeDefaultHeightDp
+ * (mOverrideDensity / mDesktopDensity) + 0.5f);
Rect outBounds = new Rect();
outBounds.set(0, 0, width, height);
@@ -1942,8 +1947,69 @@
return outBounds;
}
+ public void createFreeformTasksWithActivities(TestDesktopOrganizer desktopOrganizer,
+ List<ActivityRecord> activityRecords, int numberOfTasks) {
+ for (int i = 0; i < numberOfTasks; i++) {
+ Rect bounds = new Rect(desktopOrganizer.getDefaultDesktopTaskBounds());
+ bounds.offset(20 * i, 20 * i);
+ desktopOrganizer.createTask(bounds);
+ }
+
+ for (int i = 0; i < numberOfTasks; i++) {
+ activityRecords.add(new TaskBuilder(mService.mTaskSupervisor)
+ .setParentTask(desktopOrganizer.mTasks.get(i))
+ .setCreateActivity(true)
+ .build()
+ .getTopMostActivity());
+ }
+
+ for (int i = 0; i < numberOfTasks; i++) {
+ activityRecords.get(i).setVisibleRequested(true);
+ }
+
+ for (int i = 0; i < numberOfTasks; i++) {
+ assertEquals(desktopOrganizer.mTasks.get(i), activityRecords.get(i).getRootTask());
+ }
+ }
+
+ public void bringHomeToFront() {
+ WindowContainerTransaction wct = new WindowContainerTransaction();
+ wct.reorder(mHomeTask.getTaskInfo().token, true /* onTop */);
+ applyTransaction(wct);
+ }
+
+ public void bringDesktopTasksToFront(WindowContainerTransaction wct) {
+ for (Task task: mTasks) {
+ wct.reorder(task.getTaskInfo().token, true /* onTop */);
+ }
+ }
+
+ public void addMoveToDesktopChanges(WindowContainerTransaction wct, Task task,
+ boolean overrideDensity) {
+ wct.setWindowingMode(task.getTaskInfo().token, WINDOWING_MODE_FREEFORM);
+ wct.reorder(task.getTaskInfo().token, true /* onTop */);
+ if (overrideDensity) {
+ wct.setDensityDpi(task.getTaskInfo().token, mOverrideDensity);
+ }
+ }
+
+ public void addMoveToFullscreen(WindowContainerTransaction wct, Task task,
+ boolean overrideDensity) {
+ wct.setWindowingMode(task.getTaskInfo().token, WINDOWING_MODE_FULLSCREEN);
+ wct.setBounds(task.getTaskInfo().token, new Rect());
+ if (overrideDensity) {
+ wct.setDensityDpi(task.getTaskInfo().token, mOverrideDensity);
+ }
+ }
+
+ private void applyTransaction(@androidx.annotation.NonNull WindowContainerTransaction wct) {
+ if (!wct.isEmpty()) {
+ mService.mWindowOrganizerController.applyTransaction(wct);
+ }
+ }
}
+
static TestWindowToken createTestWindowToken(int type, DisplayContent dc) {
return createTestWindowToken(type, dc, false /* persistOnEmpty */);
}
diff --git a/telecomm/java/android/telecom/PhoneAccount.java b/telecomm/java/android/telecom/PhoneAccount.java
index 63db297..b7706a9 100644
--- a/telecomm/java/android/telecom/PhoneAccount.java
+++ b/telecomm/java/android/telecom/PhoneAccount.java
@@ -1283,6 +1283,17 @@
sb.append(mExtras);
sb.append(" GroupId: ");
sb.append(Log.pii(mGroupId));
+ sb.append(" SC Restrictions: ");
+ if (hasSimultaneousCallingRestriction()) {
+ sb.append("[ ");
+ for (PhoneAccountHandle handle : mSimultaneousCallingRestriction) {
+ sb.append(handle);
+ sb.append(" ");
+ }
+ sb.append("]");
+ } else {
+ sb.append("[NONE]");
+ }
sb.append("]");
return sb.toString();
}
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index a73c46b..e5a94c3 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -2179,6 +2179,14 @@
*/
public static final String KEY_MMS_NETWORK_RELEASE_TIMEOUT_MILLIS_INT =
"mms_network_release_timeout_millis_int";
+ /**
+ * Maximum size in bytes of the PDU to send or download when connected to a non-terrestrial
+ * network. MmsService will return a result code of MMS_ERROR_TOO_LARGE_FOR_TRANSPORT if
+ * the PDU exceeds this limit when connected to a non-terrestrial network.
+ * @hide
+ */
+ public static final String KEY_MMS_MAX_NTN_PAYLOAD_SIZE_BYTES_INT =
+ "mms_max_ntn_payload_size_bytes_int";
/**
* The flatten {@link android.content.ComponentName componentName} of the activity that can
@@ -10376,6 +10384,7 @@
sDefaults.putInt(KEY_MMS_SMS_TO_MMS_TEXT_THRESHOLD_INT, -1);
sDefaults.putInt(KEY_MMS_SUBJECT_MAX_LENGTH_INT, 40);
sDefaults.putInt(KEY_MMS_NETWORK_RELEASE_TIMEOUT_MILLIS_INT, 5 * 1000);
+ sDefaults.putInt(KEY_MMS_MAX_NTN_PAYLOAD_SIZE_BYTES_INT, 3 * 1000);
sDefaults.putString(KEY_MMS_EMAIL_GATEWAY_NUMBER_STRING, "");
sDefaults.putString(KEY_MMS_HTTP_PARAMS_STRING, "");
sDefaults.putString(KEY_MMS_NAI_SUFFIX_STRING, "");
diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java
index c958aba..b7baabf 100644
--- a/telephony/java/android/telephony/SmsManager.java
+++ b/telephony/java/android/telephony/SmsManager.java
@@ -3123,6 +3123,12 @@
@FlaggedApi(Flags.FLAG_MMS_DISABLED_ERROR)
public static final int MMS_ERROR_MMS_DISABLED_BY_CARRIER = 12;
+ /**
+ * The MMS pdu was too large to send or too large to download over the current connection.
+ * @hide
+ */
+ public static final int MMS_ERROR_TOO_LARGE_FOR_TRANSPORT = 13;
+
/** Intent extra name for MMS sending result data in byte array type */
public static final String EXTRA_MMS_DATA = "android.telephony.extra.MMS_DATA";
/** Intent extra name for HTTP status code for MMS HTTP failure in integer type */
diff --git a/telephony/java/android/telephony/satellite/SatelliteDatagramCallback.java b/telephony/java/android/telephony/satellite/SatelliteDatagramCallback.java
index 8e79ca5..9aaa986 100644
--- a/telephony/java/android/telephony/satellite/SatelliteDatagramCallback.java
+++ b/telephony/java/android/telephony/satellite/SatelliteDatagramCallback.java
@@ -28,7 +28,7 @@
/**
* A callback class for listening to satellite datagrams.
* {@link SatelliteDatagramCallback} is registered to telephony when an app which invokes
- * {@link SatelliteManager#registerForSatelliteDatagram(Executor, SatelliteDatagramCallback)},
+ * {@link SatelliteManager#registerForIncomingDatagram(Executor, SatelliteDatagramCallback)},
* and {@link #onSatelliteDatagramReceived(long, SatelliteDatagram, int, Consumer)} will be invoked
* when a new datagram is received from satellite.
*
diff --git a/telephony/java/android/telephony/satellite/SatelliteManager.java b/telephony/java/android/telephony/satellite/SatelliteManager.java
index a1ac477..b97822a 100644
--- a/telephony/java/android/telephony/satellite/SatelliteManager.java
+++ b/telephony/java/android/telephony/satellite/SatelliteManager.java
@@ -146,7 +146,7 @@
/**
* Bundle key to get the response from
- * {@link #requestIsSatelliteEnabled(Executor, OutcomeReceiver)}.
+ * {@link #requestIsEnabled(Executor, OutcomeReceiver)}.
* @hide
*/
@@ -162,7 +162,7 @@
/**
* Bundle key to get the response from
- * {@link #requestIsSatelliteSupported(Executor, OutcomeReceiver)}.
+ * {@link #requestIsSupported(Executor, OutcomeReceiver)}.
* @hide
*/
@@ -170,7 +170,7 @@
/**
* Bundle key to get the response from
- * {@link #requestSatelliteCapabilities(Executor, OutcomeReceiver)}.
+ * {@link #requestCapabilities(Executor, OutcomeReceiver)}.
* @hide
*/
@@ -178,7 +178,7 @@
/**
* Bundle key to get the response from
- * {@link #requestIsSatelliteProvisioned(Executor, OutcomeReceiver)}.
+ * {@link #requestIsProvisioned(Executor, OutcomeReceiver)}.
* @hide
*/
@@ -186,7 +186,7 @@
/**
* Bundle key to get the response from
- * {@link #requestIsSatelliteCommunicationAllowedForCurrentLocation(Executor, OutcomeReceiver)}.
+ * {@link #requestIsCommunicationAllowedForCurrentLocation(Executor, OutcomeReceiver)}.
* @hide
*/
@@ -493,7 +493,7 @@
*/
@RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
@FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
- public void requestSatelliteEnabled(boolean enableSatellite, boolean enableDemoMode,
+ public void requestEnabled(boolean enableSatellite, boolean enableDemoMode,
@NonNull @CallbackExecutor Executor executor,
@SatelliteResult @NonNull Consumer<Integer> resultListener) {
Objects.requireNonNull(executor);
@@ -535,7 +535,7 @@
*/
@RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
@FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
- public void requestIsSatelliteEnabled(@NonNull @CallbackExecutor Executor executor,
+ public void requestIsEnabled(@NonNull @CallbackExecutor Executor executor,
@NonNull OutcomeReceiver<Boolean, SatelliteException> callback) {
Objects.requireNonNull(executor);
Objects.requireNonNull(callback);
@@ -647,7 +647,7 @@
* will return a {@link SatelliteException} with the {@link SatelliteResult}.
*/
@FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
- public void requestIsSatelliteSupported(@NonNull @CallbackExecutor Executor executor,
+ public void requestIsSupported(@NonNull @CallbackExecutor Executor executor,
@NonNull OutcomeReceiver<Boolean, SatelliteException> callback) {
Objects.requireNonNull(executor);
Objects.requireNonNull(callback);
@@ -701,7 +701,7 @@
*/
@RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
@FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
- public void requestSatelliteCapabilities(@NonNull @CallbackExecutor Executor executor,
+ public void requestCapabilities(@NonNull @CallbackExecutor Executor executor,
@NonNull OutcomeReceiver<SatelliteCapabilities, SatelliteException> callback) {
Objects.requireNonNull(executor);
Objects.requireNonNull(callback);
@@ -967,7 +967,8 @@
*/
@RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
@FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
- public void startSatelliteTransmissionUpdates(@NonNull @CallbackExecutor Executor executor,
+ @SuppressWarnings("SamShouldBeLast")
+ public void startTransmissionUpdates(@NonNull @CallbackExecutor Executor executor,
@SatelliteResult @NonNull Consumer<Integer> resultListener,
@NonNull SatelliteTransmissionUpdateCallback callback) {
Objects.requireNonNull(executor);
@@ -1029,7 +1030,7 @@
* {@link #SATELLITE_RESULT_SUCCESS}. All other results that this operation failed.
*
* @param callback The callback that was passed to {@link
- * #startSatelliteTransmissionUpdates(Executor, Consumer, SatelliteTransmissionUpdateCallback)}.
+ * #startTransmissionUpdates(Executor, Consumer, SatelliteTransmissionUpdateCallback)}.
* @param executor The executor on which the error code listener will be called.
* @param resultListener Listener for the {@link SatelliteResult} result of the operation.
*
@@ -1037,13 +1038,14 @@
*/
@RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
@FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
- public void stopSatelliteTransmissionUpdates(
- @NonNull SatelliteTransmissionUpdateCallback callback,
- @NonNull @CallbackExecutor Executor executor,
- @SatelliteResult @NonNull Consumer<Integer> resultListener) {
+ public void stopTransmissionUpdates(@NonNull SatelliteTransmissionUpdateCallback callback,
+ @SuppressWarnings("ListenerLast") @NonNull @CallbackExecutor Executor executor,
+ @SuppressWarnings("ListenerLast") @SatelliteResult @NonNull
+ Consumer<Integer> resultListener) {
Objects.requireNonNull(callback);
Objects.requireNonNull(executor);
Objects.requireNonNull(resultListener);
+
ISatelliteTransmissionUpdateCallback internalCallback =
sSatelliteTransmissionUpdateCallbackMap.remove(callback);
@@ -1094,7 +1096,7 @@
*/
@RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
@FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
- public void provisionSatelliteService(@NonNull String token, @NonNull byte[] provisionData,
+ public void provisionService(@NonNull String token, @NonNull byte[] provisionData,
@Nullable CancellationSignal cancellationSignal,
@NonNull @CallbackExecutor Executor executor,
@SatelliteResult @NonNull Consumer<Integer> resultListener) {
@@ -1135,11 +1137,11 @@
* {@link SatelliteProvisionStateCallback#onSatelliteProvisionStateChanged(boolean)}
* should report as deprovisioned.
* For provisioning satellite service, refer to
- * {@link #provisionSatelliteService(String, byte[], CancellationSignal, Executor, Consumer)}
+ * {@link #provisionService(String, byte[], CancellationSignal, Executor, Consumer)}
*
* @param token The token of the device/subscription to be deprovisioned.
* This should match with the token passed as input in
- * {@link #provisionSatelliteService(String, byte[], CancellationSignal, Executor,
+ * {@link #provisionService(String, byte[], CancellationSignal, Executor,
* Consumer)}
* @param resultListener Listener for the {@link SatelliteResult} result of the operation.
*
@@ -1147,7 +1149,7 @@
*/
@RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
@FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
- public void deprovisionSatelliteService(@NonNull String token,
+ public void deprovisionService(@NonNull String token,
@NonNull @CallbackExecutor Executor executor,
@SatelliteResult @NonNull Consumer<Integer> resultListener) {
Objects.requireNonNull(token);
@@ -1188,7 +1190,7 @@
*/
@RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
@FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
- @SatelliteResult public int registerForSatelliteProvisionStateChanged(
+ @SatelliteResult public int registerForProvisionStateChanged(
@NonNull @CallbackExecutor Executor executor,
@NonNull SatelliteProvisionStateCallback callback) {
Objects.requireNonNull(executor);
@@ -1224,14 +1226,14 @@
* If callback was not registered before, the request will be ignored.
*
* @param callback The callback that was passed to
- * {@link #registerForSatelliteProvisionStateChanged(Executor, SatelliteProvisionStateCallback)}
+ * {@link #registerForProvisionStateChanged(Executor, SatelliteProvisionStateCallback)}
*
* @throws SecurityException if the caller doesn't have required permission.
* @throws IllegalStateException if the Telephony process is not currently available.
*/
@RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
@FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
- public void unregisterForSatelliteProvisionStateChanged(
+ public void unregisterForProvisionStateChanged(
@NonNull SatelliteProvisionStateCallback callback) {
Objects.requireNonNull(callback);
ISatelliteProvisionStateCallback internalCallback =
@@ -1243,13 +1245,13 @@
if (internalCallback != null) {
telephony.unregisterForSatelliteProvisionStateChanged(mSubId, internalCallback);
} else {
- loge("unregisterForSatelliteProvisionStateChanged: No internal callback.");
+ loge("unregisterForProvisionStateChanged: No internal callback.");
}
} else {
throw new IllegalStateException("telephony service is null.");
}
} catch (RemoteException ex) {
- loge("unregisterForSatelliteProvisionStateChanged() RemoteException: " + ex);
+ loge("unregisterForProvisionStateChanged() RemoteException: " + ex);
ex.rethrowAsRuntimeException();
}
}
@@ -1269,7 +1271,7 @@
*/
@RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
@FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
- public void requestIsSatelliteProvisioned(@NonNull @CallbackExecutor Executor executor,
+ public void requestIsProvisioned(@NonNull @CallbackExecutor Executor executor,
@NonNull OutcomeReceiver<Boolean, SatelliteException> callback) {
Objects.requireNonNull(executor);
Objects.requireNonNull(callback);
@@ -1322,7 +1324,7 @@
*/
@RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
@FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
- @SatelliteResult public int registerForSatelliteModemStateChanged(
+ @SatelliteResult public int registerForModemStateChanged(
@NonNull @CallbackExecutor Executor executor,
@NonNull SatelliteModemStateCallback callback) {
Objects.requireNonNull(executor);
@@ -1356,14 +1358,14 @@
* If callback was not registered before, the request will be ignored.
*
* @param callback The callback that was passed to
- * {@link #registerForSatelliteModemStateChanged(Executor, SatelliteModemStateCallback)}.
+ * {@link #registerForModemStateChanged(Executor, SatelliteModemStateCallback)}.
*
* @throws SecurityException if the caller doesn't have required permission.
* @throws IllegalStateException if the Telephony process is not currently available.
*/
@RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
@FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
- public void unregisterForSatelliteModemStateChanged(
+ public void unregisterForModemStateChanged(
@NonNull SatelliteModemStateCallback callback) {
Objects.requireNonNull(callback);
ISatelliteModemStateCallback internalCallback = sSatelliteModemStateCallbackMap.remove(
@@ -1373,15 +1375,15 @@
ITelephony telephony = getITelephony();
if (telephony != null) {
if (internalCallback != null) {
- telephony.unregisterForSatelliteModemStateChanged(mSubId, internalCallback);
+ telephony.unregisterForModemStateChanged(mSubId, internalCallback);
} else {
- loge("unregisterForSatelliteModemStateChanged: No internal callback.");
+ loge("unregisterForModemStateChanged: No internal callback.");
}
} else {
throw new IllegalStateException("telephony service is null.");
}
} catch (RemoteException ex) {
- loge("unregisterForSatelliteModemStateChanged() RemoteException:" + ex);
+ loge("unregisterForModemStateChanged() RemoteException:" + ex);
ex.rethrowAsRuntimeException();
}
}
@@ -1390,7 +1392,7 @@
* Register to receive incoming datagrams over satellite.
*
* To poll for pending satellite datagrams, refer to
- * {@link #pollPendingSatelliteDatagrams(Executor, Consumer)}
+ * {@link #pollPendingDatagrams(Executor, Consumer)}
*
* @param executor The executor on which the callback will be called.
* @param callback The callback to handle incoming datagrams over satellite.
@@ -1403,7 +1405,7 @@
*/
@RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
@FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
- @SatelliteResult public int registerForSatelliteDatagram(
+ @SatelliteResult public int registerForIncomingDatagram(
@NonNull @CallbackExecutor Executor executor,
@NonNull SatelliteDatagramCallback callback) {
Objects.requireNonNull(executor);
@@ -1436,12 +1438,12 @@
}
};
sSatelliteDatagramCallbackMap.put(callback, internalCallback);
- return telephony.registerForSatelliteDatagram(mSubId, internalCallback);
+ return telephony.registerForIncomingDatagram(mSubId, internalCallback);
} else {
throw new IllegalStateException("telephony service is null.");
}
} catch (RemoteException ex) {
- loge("registerForSatelliteDatagram() RemoteException:" + ex);
+ loge("registerForIncomingDatagram() RemoteException:" + ex);
ex.rethrowAsRuntimeException();
}
return SATELLITE_RESULT_REQUEST_FAILED;
@@ -1452,14 +1454,14 @@
* If callback was not registered before, the request will be ignored.
*
* @param callback The callback that was passed to
- * {@link #registerForSatelliteDatagram(Executor, SatelliteDatagramCallback)}.
+ * {@link #registerForIncomingDatagram(Executor, SatelliteDatagramCallback)}.
*
* @throws SecurityException if the caller doesn't have required permission.
* @throws IllegalStateException if the Telephony process is not currently available.
*/
@RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
@FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
- public void unregisterForSatelliteDatagram(@NonNull SatelliteDatagramCallback callback) {
+ public void unregisterForIncomingDatagram(@NonNull SatelliteDatagramCallback callback) {
Objects.requireNonNull(callback);
ISatelliteDatagramCallback internalCallback =
sSatelliteDatagramCallbackMap.remove(callback);
@@ -1468,15 +1470,15 @@
ITelephony telephony = getITelephony();
if (telephony != null) {
if (internalCallback != null) {
- telephony.unregisterForSatelliteDatagram(mSubId, internalCallback);
+ telephony.unregisterForIncomingDatagram(mSubId, internalCallback);
} else {
- loge("unregisterForSatelliteDatagram: No internal callback.");
+ loge("unregisterForIncomingDatagram: No internal callback.");
}
} else {
throw new IllegalStateException("telephony service is null.");
}
} catch (RemoteException ex) {
- loge("unregisterForSatelliteDatagram() RemoteException:" + ex);
+ loge("unregisterForIncomingDatagram() RemoteException:" + ex);
ex.rethrowAsRuntimeException();
}
}
@@ -1497,7 +1499,7 @@
*/
@RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
@FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
- public void pollPendingSatelliteDatagrams(@NonNull @CallbackExecutor Executor executor,
+ public void pollPendingDatagrams(@NonNull @CallbackExecutor Executor executor,
@SatelliteResult @NonNull Consumer<Integer> resultListener) {
Objects.requireNonNull(executor);
Objects.requireNonNull(resultListener);
@@ -1512,13 +1514,13 @@
() -> resultListener.accept(result)));
}
};
- telephony.pollPendingSatelliteDatagrams(mSubId, internalCallback);
+ telephony.pollPendingDatagrams(mSubId, internalCallback);
} else {
executor.execute(() -> Binder.withCleanCallingIdentity(
() -> resultListener.accept(SATELLITE_RESULT_ILLEGAL_STATE)));
}
} catch (RemoteException ex) {
- loge("pollPendingSatelliteDatagrams() RemoteException:" + ex);
+ loge("pollPendingDatagrams() RemoteException:" + ex);
ex.rethrowAsRuntimeException();
}
}
@@ -1550,7 +1552,7 @@
*/
@RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
@FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
- public void sendSatelliteDatagram(@DatagramType int datagramType,
+ public void sendDatagram(@DatagramType int datagramType,
@NonNull SatelliteDatagram datagram, boolean needFullScreenPointingUI,
@NonNull @CallbackExecutor Executor executor,
@SatelliteResult @NonNull Consumer<Integer> resultListener) {
@@ -1568,14 +1570,14 @@
() -> resultListener.accept(result)));
}
};
- telephony.sendSatelliteDatagram(mSubId, datagramType, datagram,
+ telephony.sendDatagram(mSubId, datagramType, datagram,
needFullScreenPointingUI, internalCallback);
} else {
executor.execute(() -> Binder.withCleanCallingIdentity(
() -> resultListener.accept(SATELLITE_RESULT_ILLEGAL_STATE)));
}
} catch (RemoteException ex) {
- loge("sendSatelliteDatagram() RemoteException:" + ex);
+ loge("sendDatagram() RemoteException:" + ex);
ex.rethrowAsRuntimeException();
}
}
@@ -1596,7 +1598,7 @@
*/
@RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
@FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
- public void requestIsSatelliteCommunicationAllowedForCurrentLocation(
+ public void requestIsCommunicationAllowedForCurrentLocation(
@NonNull @CallbackExecutor Executor executor,
@NonNull OutcomeReceiver<Boolean, SatelliteException> callback) {
Objects.requireNonNull(executor);
@@ -1626,14 +1628,14 @@
}
}
};
- telephony.requestIsSatelliteCommunicationAllowedForCurrentLocation(mSubId,
+ telephony.requestIsCommunicationAllowedForCurrentLocation(mSubId,
receiver);
} else {
executor.execute(() -> Binder.withCleanCallingIdentity(() -> callback.onError(
new SatelliteException(SATELLITE_RESULT_ILLEGAL_STATE))));
}
} catch (RemoteException ex) {
- loge("requestIsSatelliteCommunicationAllowedForCurrentLocation() RemoteException: "
+ loge("requestIsCommunicationAllowedForCurrentLocation() RemoteException: "
+ ex);
ex.rethrowAsRuntimeException();
}
@@ -1733,7 +1735,7 @@
* <ul>
* <li>Users want to enable it.</li>
* <li>There is no satellite communication restriction, which is added by
- * {@link #addSatelliteAttachRestrictionForCarrier(int, int, Executor, Consumer)}</li>
+ * {@link #addAttachRestrictionForCarrier(int, int, Executor, Consumer)}</li>
* <li>The carrier config {@link
* android.telephony.CarrierConfigManager#KEY_SATELLITE_ATTACH_SUPPORTED_BOOL} is set to
* {@code true}.</li>
@@ -1749,17 +1751,17 @@
*/
@RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
@FlaggedApi(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG)
- public void requestSatelliteAttachEnabledForCarrier(int subId, boolean enableSatellite,
+ public void requestAttachEnabledForCarrier(int subId, boolean enableSatellite,
@NonNull @CallbackExecutor Executor executor,
@SatelliteResult @NonNull Consumer<Integer> resultListener) {
Objects.requireNonNull(executor);
Objects.requireNonNull(resultListener);
if (enableSatellite) {
- removeSatelliteAttachRestrictionForCarrier(subId,
+ removeAttachRestrictionForCarrier(subId,
SATELLITE_COMMUNICATION_RESTRICTION_REASON_USER, executor, resultListener);
} else {
- addSatelliteAttachRestrictionForCarrier(subId,
+ addAttachRestrictionForCarrier(subId,
SATELLITE_COMMUNICATION_RESTRICTION_REASON_USER, executor, resultListener);
}
}
@@ -1783,13 +1785,13 @@
*/
@RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
@FlaggedApi(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG)
- public void requestIsSatelliteAttachEnabledForCarrier(int subId,
+ public void requestIsAttachEnabledForCarrier(int subId,
@NonNull @CallbackExecutor Executor executor,
@NonNull OutcomeReceiver<Boolean, SatelliteException> callback) {
Objects.requireNonNull(executor);
Objects.requireNonNull(callback);
- Set<Integer> restrictionReason = getSatelliteAttachRestrictionReasonsForCarrier(subId);
+ Set<Integer> restrictionReason = getAttachRestrictionReasonsForCarrier(subId);
executor.execute(() -> callback.onResult(
!restrictionReason.contains(SATELLITE_COMMUNICATION_RESTRICTION_REASON_USER)));
}
@@ -1808,7 +1810,7 @@
*/
@RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
@FlaggedApi(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG)
- public void addSatelliteAttachRestrictionForCarrier(int subId,
+ public void addAttachRestrictionForCarrier(int subId,
@SatelliteCommunicationRestrictionReason int reason,
@NonNull @CallbackExecutor Executor executor,
@SatelliteResult @NonNull Consumer<Integer> resultListener) {
@@ -1826,13 +1828,13 @@
() -> resultListener.accept(result)));
}
};
- telephony.addSatelliteAttachRestrictionForCarrier(subId, reason, errorCallback);
+ telephony.addAttachRestrictionForCarrier(subId, reason, errorCallback);
} else {
executor.execute(() -> Binder.withCleanCallingIdentity(
() -> resultListener.accept(SATELLITE_RESULT_ILLEGAL_STATE)));
}
} catch (RemoteException ex) {
- loge("addSatelliteAttachRestrictionForCarrier() RemoteException:" + ex);
+ loge("addAttachRestrictionForCarrier() RemoteException:" + ex);
ex.rethrowAsRuntimeException();
}
}
@@ -1851,7 +1853,7 @@
*/
@RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
@FlaggedApi(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG)
- public void removeSatelliteAttachRestrictionForCarrier(int subId,
+ public void removeAttachRestrictionForCarrier(int subId,
@SatelliteCommunicationRestrictionReason int reason,
@NonNull @CallbackExecutor Executor executor,
@SatelliteResult @NonNull Consumer<Integer> resultListener) {
@@ -1869,20 +1871,20 @@
() -> resultListener.accept(result)));
}
};
- telephony.removeSatelliteAttachRestrictionForCarrier(subId, reason, errorCallback);
+ telephony.removeAttachRestrictionForCarrier(subId, reason, errorCallback);
} else {
executor.execute(() -> Binder.withCleanCallingIdentity(
() -> resultListener.accept(SATELLITE_RESULT_ILLEGAL_STATE)));
}
} catch (RemoteException ex) {
- loge("removeSatelliteAttachRestrictionForCarrier() RemoteException:" + ex);
+ loge("removeAttachRestrictionForCarrier() RemoteException:" + ex);
ex.rethrowAsRuntimeException();
}
}
/**
* Get reasons for disallowing satellite attach, as requested by
- * {@link #addSatelliteAttachRestrictionForCarrier(int, int, Executor, Consumer)}
+ * {@link #addAttachRestrictionForCarrier(int, int, Executor, Consumer)}
*
* @param subId The subscription ID of the carrier.
* @return Set of reasons for disallowing satellite communication.
@@ -1894,7 +1896,7 @@
@RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
@SatelliteCommunicationRestrictionReason
@FlaggedApi(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG)
- @NonNull public Set<Integer> getSatelliteAttachRestrictionReasonsForCarrier(int subId) {
+ @NonNull public Set<Integer> getAttachRestrictionReasonsForCarrier(int subId) {
if (!SubscriptionManager.isValidSubscriptionId(subId)) {
throw new IllegalArgumentException("Invalid subscription ID");
}
@@ -1903,7 +1905,7 @@
ITelephony telephony = getITelephony();
if (telephony != null) {
int[] receivedArray =
- telephony.getSatelliteAttachRestrictionReasonsForCarrier(subId);
+ telephony.getAttachRestrictionReasonsForCarrier(subId);
if (receivedArray.length == 0) {
logd("receivedArray is empty, create empty set");
return new HashSet<>();
@@ -1914,7 +1916,7 @@
throw new IllegalStateException("Telephony service is null.");
}
} catch (RemoteException ex) {
- loge("getSatelliteAttachRestrictionReasonsForCarrier() RemoteException: " + ex);
+ loge("getAttachRestrictionReasonsForCarrier() RemoteException: " + ex);
ex.rethrowAsRuntimeException();
}
return new HashSet<>();
@@ -2090,7 +2092,7 @@
*/
@RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
@FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
- @SatelliteResult public int registerForSatelliteCapabilitiesChanged(
+ @SatelliteResult public int registerForCapabilitiesChanged(
@NonNull @CallbackExecutor Executor executor,
@NonNull SatelliteCapabilitiesCallback callback) {
Objects.requireNonNull(executor);
@@ -2110,12 +2112,12 @@
}
};
sSatelliteCapabilitiesCallbackMap.put(callback, internalCallback);
- return telephony.registerForSatelliteCapabilitiesChanged(mSubId, internalCallback);
+ return telephony.registerForCapabilitiesChanged(mSubId, internalCallback);
} else {
throw new IllegalStateException("Telephony service is null.");
}
} catch (RemoteException ex) {
- loge("registerForSatelliteCapabilitiesChanged() RemoteException: " + ex);
+ loge("registerForCapabilitiesChanged() RemoteException: " + ex);
ex.rethrowAsRuntimeException();
}
return SATELLITE_RESULT_REQUEST_FAILED;
@@ -2126,14 +2128,14 @@
* If callback was not registered before, the request will be ignored.
*
* @param callback The callback that was passed to.
- * {@link #registerForSatelliteCapabilitiesChanged(Executor, SatelliteCapabilitiesCallback)}.
+ * {@link #registerForCapabilitiesChanged(Executor, SatelliteCapabilitiesCallback)}.
*
* @throws SecurityException if the caller doesn't have required permission.
* @throws IllegalStateException if the Telephony process is not currently available.
*/
@RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
@FlaggedApi(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG)
- public void unregisterForSatelliteCapabilitiesChanged(
+ public void unregisterForCapabilitiesChanged(
@NonNull SatelliteCapabilitiesCallback callback) {
Objects.requireNonNull(callback);
ISatelliteCapabilitiesCallback internalCallback =
@@ -2143,15 +2145,15 @@
ITelephony telephony = getITelephony();
if (telephony != null) {
if (internalCallback != null) {
- telephony.unregisterForSatelliteCapabilitiesChanged(mSubId, internalCallback);
+ telephony.unregisterForCapabilitiesChanged(mSubId, internalCallback);
} else {
- loge("unregisterForSatelliteCapabilitiesChanged: No internal callback.");
+ loge("unregisterForCapabilitiesChanged: No internal callback.");
}
} else {
throw new IllegalStateException("Telephony service is null.");
}
} catch (RemoteException ex) {
- loge("unregisterForSatelliteCapabilitiesChanged() RemoteException: " + ex);
+ loge("unregisterForCapabilitiesChanged() RemoteException: " + ex);
ex.rethrowAsRuntimeException();
}
}
@@ -2166,7 +2168,7 @@
*/
@RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
@FlaggedApi(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG)
- @NonNull public List<String> getAllSatellitePlmnsForCarrier(int subId) {
+ @NonNull public List<String> getSatellitePlmnsForCarrier(int subId) {
if (!SubscriptionManager.isValidSubscriptionId(subId)) {
throw new IllegalArgumentException("Invalid subscription ID");
}
@@ -2174,12 +2176,12 @@
try {
ITelephony telephony = getITelephony();
if (telephony != null) {
- return telephony.getAllSatellitePlmnsForCarrier(subId);
+ return telephony.getSatellitePlmnsForCarrier(subId);
} else {
throw new IllegalStateException("Telephony service is null.");
}
} catch (RemoteException ex) {
- loge("getAllSatellitePlmnsForCarrier() RemoteException: " + ex);
+ loge("getSatellitePlmnsForCarrier() RemoteException: " + ex);
ex.rethrowAsRuntimeException();
}
return new ArrayList<>();
diff --git a/telephony/java/android/telephony/satellite/stub/INtnSignalStrengthConsumer.aidl b/telephony/java/android/telephony/satellite/stub/INtnSignalStrengthConsumer.aidl
index b7712bd..655da740 100644
--- a/telephony/java/android/telephony/satellite/stub/INtnSignalStrengthConsumer.aidl
+++ b/telephony/java/android/telephony/satellite/stub/INtnSignalStrengthConsumer.aidl
@@ -16,7 +16,7 @@
package android.telephony.satellite.stub;
-import android.telephony.satellite.NtnSignalStrength;
+import android.telephony.satellite.stub.NtnSignalStrength;
/**
* Consumer pattern for a request that receives the signal strength of non-terrestrial network from
diff --git a/telephony/java/android/telephony/satellite/stub/SatelliteImplBase.java b/telephony/java/android/telephony/satellite/stub/SatelliteImplBase.java
index c0d0830..abacd15 100644
--- a/telephony/java/android/telephony/satellite/stub/SatelliteImplBase.java
+++ b/telephony/java/android/telephony/satellite/stub/SatelliteImplBase.java
@@ -181,7 +181,7 @@
executeMethodAsync(
() -> SatelliteImplBase.this
.sendSatelliteDatagram(datagram, isEmergency, resultCallback),
- "sendSatelliteDatagram");
+ "sendDatagram");
}
@Override
@@ -201,7 +201,7 @@
() -> SatelliteImplBase.this
.requestIsSatelliteCommunicationAllowedForCurrentLocation(
resultCallback, callback),
- "requestIsSatelliteCommunicationAllowedForCurrentLocation");
+ "requestIsCommunicationAllowedForCurrentLocation");
}
@Override
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 24296f4..43eb111 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -2907,7 +2907,7 @@
*/
@JavaPassthrough(annotation="@android.annotation.RequiresPermission("
+ "android.Manifest.permission.SATELLITE_COMMUNICATION)")
- void unregisterForSatelliteModemStateChanged(int subId, ISatelliteModemStateCallback callback);
+ void unregisterForModemStateChanged(int subId, ISatelliteModemStateCallback callback);
/**
* Register to receive incoming datagrams over satellite.
@@ -2919,18 +2919,18 @@
*/
@JavaPassthrough(annotation="@android.annotation.RequiresPermission("
+ "android.Manifest.permission.SATELLITE_COMMUNICATION)")
- int registerForSatelliteDatagram(int subId, ISatelliteDatagramCallback callback);
+ int registerForIncomingDatagram(int subId, ISatelliteDatagramCallback callback);
/**
* Unregister to stop receiving incoming datagrams over satellite.
* If callback was not registered before, the request will be ignored.
*
* @param subId The subId of the subscription to unregister for incoming satellite datagrams.
- * @param callback The callback that was passed to registerForSatelliteDatagram.
+ * @param callback The callback that was passed to registerForIncomingDatagram.
*/
@JavaPassthrough(annotation="@android.annotation.RequiresPermission("
+ "android.Manifest.permission.SATELLITE_COMMUNICATION)")
- void unregisterForSatelliteDatagram(int subId, ISatelliteDatagramCallback callback);
+ void unregisterForIncomingDatagram(int subId, ISatelliteDatagramCallback callback);
/**
* Poll pending satellite datagrams over satellite.
@@ -2940,7 +2940,7 @@
*/
@JavaPassthrough(annotation="@android.annotation.RequiresPermission("
+ "android.Manifest.permission.SATELLITE_COMMUNICATION)")
- void pollPendingSatelliteDatagrams(int subId, IIntegerConsumer callback);
+ void pollPendingDatagrams(int subId, IIntegerConsumer callback);
/**
* Send datagram over satellite.
@@ -2954,9 +2954,8 @@
*/
@JavaPassthrough(annotation="@android.annotation.RequiresPermission("
+ "android.Manifest.permission.SATELLITE_COMMUNICATION)")
- void sendSatelliteDatagram(int subId, int datagramType,
- in SatelliteDatagram datagram, in boolean needFullScreenPointingUI,
- IIntegerConsumer callback);
+ void sendDatagram(int subId, int datagramType, in SatelliteDatagram datagram,
+ in boolean needFullScreenPointingUI, IIntegerConsumer callback);
/**
* Request to get whether satellite communication is allowed for the current location.
@@ -2968,8 +2967,7 @@
*/
@JavaPassthrough(annotation="@android.annotation.RequiresPermission("
+ "android.Manifest.permission.SATELLITE_COMMUNICATION)")
- void requestIsSatelliteCommunicationAllowedForCurrentLocation(int subId,
- in ResultReceiver receiver);
+ void requestIsCommunicationAllowedForCurrentLocation(int subId, in ResultReceiver receiver);
/**
* Request to get the time after which the satellite will be visible.
@@ -3104,8 +3102,7 @@
*/
@JavaPassthrough(annotation="@android.annotation.RequiresPermission("
+ "android.Manifest.permission.SATELLITE_COMMUNICATION)")
- void addSatelliteAttachRestrictionForCarrier(int subId, int reason,
- in IIntegerConsumer callback);
+ void addAttachRestrictionForCarrier(int subId, int reason, in IIntegerConsumer callback);
/**
* Remove a restriction reason for disallowing satellite communication.
@@ -3117,12 +3114,11 @@
*/
@JavaPassthrough(annotation="@android.annotation.RequiresPermission("
+ "android.Manifest.permission.SATELLITE_COMMUNICATION)")
- void removeSatelliteAttachRestrictionForCarrier(int subId, int reason,
- in IIntegerConsumer callback);
+ void removeAttachRestrictionForCarrier(int subId, int reason, in IIntegerConsumer callback);
/**
* Get reasons for disallowing satellite communication, as requested by
- * {@link #addSatelliteAttachRestrictionForCarrier(int, int)}.
+ * {@link #addAttachRestrictionForCarrier(int, int)}.
*
* @param subId The subId of the subscription to request for.
*
@@ -3130,7 +3126,7 @@
*/
@JavaPassthrough(annotation="@android.annotation.RequiresPermission("
+ "android.Manifest.permission.SATELLITE_COMMUNICATION)")
- int[] getSatelliteAttachRestrictionReasonsForCarrier(int subId);
+ int[] getAttachRestrictionReasonsForCarrier(int subId);
/**
* Request to get the signal strength of the satellite connection.
@@ -3170,8 +3166,7 @@
*/
@JavaPassthrough(annotation="@android.annotation.RequiresPermission("
+ "android.Manifest.permission.SATELLITE_COMMUNICATION)")
- void unregisterForNtnSignalStrengthChanged(int subId,
- in INtnSignalStrengthCallback callback);
+ void unregisterForNtnSignalStrengthChanged(int subId, in INtnSignalStrengthCallback callback);
/**
* Registers for satellite capabilities change event from the satellite service.
@@ -3181,19 +3176,18 @@
*/
@JavaPassthrough(annotation="@android.annotation.RequiresPermission("
+ "android.Manifest.permission.SATELLITE_COMMUNICATION)")
- int registerForSatelliteCapabilitiesChanged(int subId,
- in ISatelliteCapabilitiesCallback callback);
+ int registerForCapabilitiesChanged(int subId, in ISatelliteCapabilitiesCallback callback);
/**
* Unregisters for satellite capabilities change event from the satellite service.
* If callback was not registered before, the request will be ignored.
*
* @param callback The callback that was passed to.
- * {@link #registerForSatelliteCapabilitiesChanged(Executor, SatelliteCapabilitiesCallback)}.
+ * {@link #registerForCapabilitiesChanged(Executor, SatelliteCapabilitiesCallback)}.
*/
@JavaPassthrough(annotation="@android.annotation.RequiresPermission("
+ "android.Manifest.permission.SATELLITE_COMMUNICATION)")
- void unregisterForSatelliteCapabilitiesChanged(int subId,
+ void unregisterForCapabilitiesChanged(int subId,
in ISatelliteCapabilitiesCallback callback);
/**
@@ -3280,5 +3274,5 @@
*/
@JavaPassthrough(annotation="@android.annotation.RequiresPermission("
+ "android.Manifest.permission.SATELLITE_COMMUNICATION)")
- List<String> getAllSatellitePlmnsForCarrier(int subId);
+ List<String> getSatellitePlmnsForCarrier(int subId);
}
diff --git a/tests/SurfaceControlViewHostTest/src/com/android/test/viewembed/EmbeddedWindowService.java b/tests/SurfaceControlViewHostTest/src/com/android/test/viewembed/EmbeddedWindowService.java
index 5aaf30a..14230fe 100644
--- a/tests/SurfaceControlViewHostTest/src/com/android/test/viewembed/EmbeddedWindowService.java
+++ b/tests/SurfaceControlViewHostTest/src/com/android/test/viewembed/EmbeddedWindowService.java
@@ -134,7 +134,7 @@
c.drawText("Remote", 250, 250, paint);
surface.unlockCanvasAndPost(c);
WindowManager wm = getSystemService(WindowManager.class);
- mInputToken = wm.registerBatchedSurfaceControlInputReceiver(displayId, hostToken,
+ wm.registerBatchedSurfaceControlInputReceiver(displayId, hostToken,
mSurfaceControl,
Choreographer.getInstance(), event -> {
Log.d(TAG, "onInputEvent-remote " + event);
@@ -147,11 +147,9 @@
@Override
public void tearDownEmbeddedSurfaceControl() {
if (mSurfaceControl != null) {
- new SurfaceControl.Transaction().remove(mSurfaceControl);
- }
- if (mInputToken != null) {
WindowManager wm = getSystemService(WindowManager.class);
- wm.unregisterSurfaceControlInputReceiver(mInputToken);
+ wm.unregisterSurfaceControlInputReceiver(mSurfaceControl);
+ new SurfaceControl.Transaction().remove(mSurfaceControl).apply();
}
}
}
diff --git a/tests/SurfaceControlViewHostTest/src/com/android/test/viewembed/SurfaceInputTestActivity.java b/tests/SurfaceControlViewHostTest/src/com/android/test/viewembed/SurfaceInputTestActivity.java
index e5f8f47..7330ec1 100644
--- a/tests/SurfaceControlViewHostTest/src/com/android/test/viewembed/SurfaceInputTestActivity.java
+++ b/tests/SurfaceControlViewHostTest/src/com/android/test/viewembed/SurfaceInputTestActivity.java
@@ -50,10 +50,11 @@
private static final String TAG = "SurfaceInputTestActivity";
private SurfaceView mLocalSurfaceView;
private SurfaceView mRemoteSurfaceView;
- private IBinder mInputToken;
private IAttachEmbeddedWindow mIAttachEmbeddedWindow;
private SurfaceControl mParentSurfaceControl;
+ private SurfaceControl mLocalSurfaceControl;
+
private final ServiceConnection mConnection = new ServiceConnection() {
// Called when the connection with the service is established
public void onServiceConnected(ComponentName className, IBinder service) {
@@ -112,30 +113,33 @@
@Override
protected void onDestroy() {
super.onDestroy();
- getWindowManager().unregisterSurfaceControlInputReceiver(mInputToken);
+ if (mLocalSurfaceControl != null) {
+ getWindowManager().unregisterSurfaceControlInputReceiver(mLocalSurfaceControl);
+ new SurfaceControl.Transaction().remove(mLocalSurfaceControl).apply();
+ }
}
private void addLocalChildSurfaceControl(AttachedSurfaceControl attachedSurfaceControl) {
- SurfaceControl surfaceControl = new SurfaceControl.Builder().setName("LocalSC")
+ mLocalSurfaceControl = new SurfaceControl.Builder().setName("LocalSC")
.setBufferSize(100, 100).build();
- attachedSurfaceControl.buildReparentTransaction(surfaceControl)
- .setVisibility(surfaceControl, true)
- .setCrop(surfaceControl, new Rect(0, 0, 100, 100))
- .setPosition(surfaceControl, 250, 1000)
- .setLayer(surfaceControl, 1).apply();
+ attachedSurfaceControl.buildReparentTransaction(mLocalSurfaceControl)
+ .setVisibility(mLocalSurfaceControl, true)
+ .setCrop(mLocalSurfaceControl, new Rect(0, 0, 100, 100))
+ .setPosition(mLocalSurfaceControl, 250, 1000)
+ .setLayer(mLocalSurfaceControl, 1).apply();
Paint paint = new Paint();
paint.setColor(Color.WHITE);
paint.setTextSize(20);
- Surface surface = new Surface(surfaceControl);
+ Surface surface = new Surface(mLocalSurfaceControl);
Canvas c = surface.lockCanvas(null);
c.drawColor(Color.GREEN);
c.drawText("Local SC", 0, 0, paint);
surface.unlockCanvasAndPost(c);
WindowManager wm = getSystemService(WindowManager.class);
- mInputToken = wm.registerBatchedSurfaceControlInputReceiver(getDisplayId(),
- attachedSurfaceControl.getHostToken(), surfaceControl,
+ wm.registerBatchedSurfaceControlInputReceiver(getDisplayId(),
+ attachedSurfaceControl.getHostToken(), mLocalSurfaceControl,
Choreographer.getInstance(), event -> {
Log.d(TAG, "onInputEvent-sc " + event);
return false;
@@ -143,8 +147,6 @@
}
private final SurfaceHolder.Callback mLocalSurfaceViewCallback = new SurfaceHolder.Callback() {
- private IBinder mInputToken;
-
@Override
public void surfaceCreated(@NonNull SurfaceHolder holder) {
Paint paint = new Paint();
@@ -157,7 +159,7 @@
holder.unlockCanvasAndPost(c);
WindowManager wm = getSystemService(WindowManager.class);
- mInputToken = wm.registerBatchedSurfaceControlInputReceiver(getDisplayId(),
+ wm.registerBatchedSurfaceControlInputReceiver(getDisplayId(),
mLocalSurfaceView.getHostToken(), mLocalSurfaceView.getSurfaceControl(),
Choreographer.getInstance(), event -> {
Log.d(TAG, "onInputEvent-local " + event);
@@ -173,9 +175,8 @@
@Override
public void surfaceDestroyed(@NonNull SurfaceHolder holder) {
- if (mInputToken != null) {
- getWindowManager().unregisterSurfaceControlInputReceiver(mInputToken);
- }
+ getWindowManager().unregisterSurfaceControlInputReceiver(
+ mLocalSurfaceView.getSurfaceControl());
}
};
diff --git a/tools/aapt2/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp
index f3f1838..642a561 100644
--- a/tools/aapt2/cmd/Link.cpp
+++ b/tools/aapt2/cmd/Link.cpp
@@ -1988,6 +1988,8 @@
context_->SetNameManglerPolicy(NameManglerPolicy{context_->GetCompilationPackage()});
context_->SetSplitNameDependencies(app_info_.split_name_dependencies);
+ std::unique_ptr<xml::XmlResource> pre_flags_filter_manifest_xml = manifest_xml->Clone();
+
FeatureFlagsFilterOptions flags_filter_options;
if (context_->GetMinSdkVersion() > SDK_UPSIDE_DOWN_CAKE) {
// For API version > U, PackageManager will dynamically read the flag values and disable
@@ -2297,7 +2299,12 @@
}
if (options_.generate_java_class_path) {
- if (!WriteManifestJavaFile(manifest_xml.get())) {
+ // The FeatureFlagsFilter may remove <permission> and <permission-group> elements that
+ // generate constants in the Manifest Java file. While we want those permissions and
+ // permission groups removed in the SDK (i.e., if a feature flag is disabled), the
+ // constants should still remain so that code referencing it (e.g., within a feature
+ // flag check) will still compile. Therefore we use the manifest XML before the filter.
+ if (!WriteManifestJavaFile(pre_flags_filter_manifest_xml.get())) {
error = true;
}
}
diff --git a/tools/aapt2/cmd/Link_test.cpp b/tools/aapt2/cmd/Link_test.cpp
index 9323f3b..6cc42f1 100644
--- a/tools/aapt2/cmd/Link_test.cpp
+++ b/tools/aapt2/cmd/Link_test.cpp
@@ -1021,9 +1021,11 @@
.AddContents(manifest_contents)
.Build();
+ const std::string app_java = GetTestPath("app-java");
auto app_link_args = LinkCommandBuilder(this)
.SetManifestFile(app_manifest)
.AddParameter("-I", android_apk)
+ .AddParameter("--java", app_java)
.AddParameter("--feature-flags", "flag=false");
const std::string app_apk = GetTestPath("app.apk");
@@ -1038,6 +1040,12 @@
ASSERT_THAT(root, NotNull());
auto maybe_removed = root->FindChild({}, "permission");
ASSERT_THAT(maybe_removed, IsNull());
+
+ // Code for the permission should be generated even if the element is removed
+ const std::string manifest_java = app_java + "/com/example/app/Manifest.java";
+ std::string manifest_java_contents;
+ ASSERT_TRUE(android::base::ReadFileToString(manifest_java, &manifest_java_contents));
+ EXPECT_THAT(manifest_java_contents, HasSubstr(" public static final String FOO=\"FOO\";"));
}
TEST_F(LinkTest, FeatureFlagEnabled_SdkAtMostUDC) {
diff --git a/tools/aapt2/link/ManifestFixer.cpp b/tools/aapt2/link/ManifestFixer.cpp
index 0b16e2c..d03f97e 100644
--- a/tools/aapt2/link/ManifestFixer.cpp
+++ b/tools/aapt2/link/ManifestFixer.cpp
@@ -415,6 +415,8 @@
intent_filter_action["action"].Action(RequiredNameIsNotEmpty);
intent_filter_action["category"].Action(RequiredNameIsNotEmpty);
intent_filter_action["data"];
+ intent_filter_action["uri-relative-filter-group"];
+ intent_filter_action["uri-relative-filter-group"]["data"];
// Common <meta-data> actions.
xml::XmlNodeAction meta_data_action;
diff --git a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/MessageQueue_host.java b/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/MessageQueue_host.java
index 2e47d48..65da4a1 100644
--- a/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/MessageQueue_host.java
+++ b/tools/hoststubgen/hoststubgen/helper-framework-runtime-src/framework/com/android/hoststubgen/nativesubstitution/MessageQueue_host.java
@@ -28,6 +28,7 @@
private final Object mPoller = new Object();
private volatile boolean mPolling;
+ private volatile boolean mPendingWake;
private void validate() {
if (mDeleted) {
@@ -62,7 +63,9 @@
synchronized (q.mPoller) {
q.mPolling = true;
try {
- if (timeoutMillis == 0) {
+ if (q.mPendingWake) {
+ // Calling with pending wake returns immediately
+ } else if (timeoutMillis == 0) {
// Calling epoll_wait() with 0 returns immediately
} else if (timeoutMillis == -1) {
q.mPoller.wait();
@@ -72,6 +75,8 @@
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
+ // Any reason for returning counts as a "wake", so clear pending
+ q.mPendingWake = false;
q.mPolling = false;
}
}
@@ -79,6 +84,7 @@
public static void nativeWake(long ptr) {
var q = getInstance(ptr);
synchronized (q.mPoller) {
+ q.mPendingWake = true;
q.mPoller.notifyAll();
}
}