Merge "Consolidate UserID+Package classes."
diff --git a/Android.bp b/Android.bp
index 0315c12..0a14565 100644
--- a/Android.bp
+++ b/Android.bp
@@ -214,6 +214,7 @@
"android.hardware.radio-V1.5-java",
"android.hardware.radio-V1.6-java",
"android.hardware.radio.data-V1-java",
+ "android.hardware.radio.ims-V1-java",
"android.hardware.radio.messaging-V1-java",
"android.hardware.radio.modem-V1-java",
"android.hardware.radio.network-V2-java",
diff --git a/apex/jobscheduler/framework/java/android/app/AlarmManager.java b/apex/jobscheduler/framework/java/android/app/AlarmManager.java
index 5a445d4..dade7c3 100644
--- a/apex/jobscheduler/framework/java/android/app/AlarmManager.java
+++ b/apex/jobscheduler/framework/java/android/app/AlarmManager.java
@@ -309,7 +309,7 @@
/**
* Callback method that is invoked by the system when the alarm time is reached.
*/
- public void onAlarm();
+ void onAlarm();
}
final class ListenerWrapper extends IAlarmListener.Stub implements Runnable {
@@ -453,7 +453,7 @@
* @see #RTC
* @see #RTC_WAKEUP
*/
- public void set(@AlarmType int type, long triggerAtMillis, PendingIntent operation) {
+ public void set(@AlarmType int type, long triggerAtMillis, @NonNull PendingIntent operation) {
setImpl(type, triggerAtMillis, legacyExactLength(), 0, 0, operation, null, null,
(Handler) null, null, null);
}
@@ -480,8 +480,8 @@
* @param targetHandler {@link Handler} on which to execute the listener's onAlarm()
* callback, or {@code null} to run that callback on the main looper.
*/
- public void set(@AlarmType int type, long triggerAtMillis, String tag, OnAlarmListener listener,
- Handler targetHandler) {
+ public void set(@AlarmType int type, long triggerAtMillis, @Nullable String tag,
+ @NonNull OnAlarmListener listener, @Nullable Handler targetHandler) {
setImpl(type, triggerAtMillis, legacyExactLength(), 0, 0, null, listener, tag,
targetHandler, null, null);
}
@@ -546,7 +546,7 @@
* @see Intent#EXTRA_ALARM_COUNT
*/
public void setRepeating(@AlarmType int type, long triggerAtMillis,
- long intervalMillis, PendingIntent operation) {
+ long intervalMillis, @NonNull PendingIntent operation) {
setImpl(type, triggerAtMillis, legacyExactLength(), intervalMillis, 0, operation,
null, null, (Handler) null, null, null);
}
@@ -602,7 +602,7 @@
* @see #RTC_WAKEUP
*/
public void setWindow(@AlarmType int type, long windowStartMillis, long windowLengthMillis,
- PendingIntent operation) {
+ @NonNull PendingIntent operation) {
setImpl(type, windowStartMillis, windowLengthMillis, 0, 0, operation,
null, null, (Handler) null, null, null);
}
@@ -625,12 +625,62 @@
* @see #setWindow(int, long, long, PendingIntent)
*/
public void setWindow(@AlarmType int type, long windowStartMillis, long windowLengthMillis,
- String tag, OnAlarmListener listener, Handler targetHandler) {
+ @Nullable String tag, @NonNull OnAlarmListener listener,
+ @Nullable Handler targetHandler) {
setImpl(type, windowStartMillis, windowLengthMillis, 0, 0, null, listener, tag,
targetHandler, null, null);
}
/**
+ * Direct callback version of {@link #setWindow(int, long, long, PendingIntent)}. Rather
+ * than supplying a PendingIntent to be sent when the alarm time is reached, this variant
+ * supplies an {@link OnAlarmListener} instance that will be invoked at that time.
+ * <p>
+ * The OnAlarmListener {@link OnAlarmListener#onAlarm() onAlarm()} method will be
+ * invoked via the specified target Executor.
+ *
+ * <p>
+ * Note: Starting with API {@link Build.VERSION_CODES#S}, apps should not pass in a window of
+ * less than 10 minutes. The system will try its best to accommodate smaller windows if the
+ * alarm is supposed to fire in the near future, but there are no guarantees and the app should
+ * expect any window smaller than 10 minutes to get elongated to 10 minutes.
+ *
+ * @see #setWindow(int, long, long, PendingIntent)
+ */
+ public void setWindow(@AlarmType int type, long windowStartMillis, long windowLengthMillis,
+ @Nullable String tag, @NonNull Executor executor, @NonNull OnAlarmListener listener) {
+ setImpl(type, windowStartMillis, windowLengthMillis, 0, 0, null, listener, tag,
+ executor, null, null);
+ }
+
+ /**
+ * Direct callback version of {@link #setWindow(int, long, long, PendingIntent)}. Rather
+ * than supplying a PendingIntent to be sent when the alarm time is reached, this variant
+ * supplies an {@link OnAlarmListener} instance that will be invoked at that time.
+ * <p>
+ * The OnAlarmListener {@link OnAlarmListener#onAlarm() onAlarm()} method will be
+ * invoked via the specified target Executor.
+ *
+ * <p>
+ * Note: Starting with API {@link Build.VERSION_CODES#S}, apps should not pass in a window of
+ * less than 10 minutes. The system will try its best to accommodate smaller windows if the
+ * alarm is supposed to fire in the near future, but there are no guarantees and the app should
+ * expect any window smaller than 10 minutes to get elongated to 10 minutes.
+ *
+ * @see #setWindow(int, long, long, PendingIntent)
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS)
+ public void setWindow(@AlarmType int type, long windowStartMillis, long windowLengthMillis,
+ @Nullable String tag, @NonNull Executor executor, @Nullable WorkSource workSource,
+ @NonNull OnAlarmListener listener) {
+ setImpl(type, windowStartMillis, windowLengthMillis, 0, 0, null, listener, tag,
+ executor, workSource, null);
+ }
+
+ /**
* Schedule an alarm that is prioritized by the system while the device is in power saving modes
* such as battery saver and device idle (doze).
*
@@ -725,7 +775,8 @@
* @see Manifest.permission#SCHEDULE_EXACT_ALARM SCHEDULE_EXACT_ALARM
*/
@RequiresPermission(value = Manifest.permission.SCHEDULE_EXACT_ALARM, conditional = true)
- public void setExact(@AlarmType int type, long triggerAtMillis, PendingIntent operation) {
+ public void setExact(@AlarmType int type, long triggerAtMillis,
+ @NonNull PendingIntent operation) {
setImpl(type, triggerAtMillis, WINDOW_EXACT, 0, 0, operation, null, null, (Handler) null,
null, null);
}
@@ -756,8 +807,8 @@
* @see Manifest.permission#SCHEDULE_EXACT_ALARM SCHEDULE_EXACT_ALARM
*/
@RequiresPermission(value = Manifest.permission.SCHEDULE_EXACT_ALARM, conditional = true)
- public void setExact(@AlarmType int type, long triggerAtMillis, String tag,
- OnAlarmListener listener, Handler targetHandler) {
+ public void setExact(@AlarmType int type, long triggerAtMillis, @Nullable String tag,
+ @NonNull OnAlarmListener listener, @Nullable Handler targetHandler) {
setImpl(type, triggerAtMillis, WINDOW_EXACT, 0, 0, null, listener, tag,
targetHandler, null, null);
}
@@ -767,8 +818,8 @@
* the given time.
* @hide
*/
- public void setIdleUntil(@AlarmType int type, long triggerAtMillis, String tag,
- OnAlarmListener listener, Handler targetHandler) {
+ public void setIdleUntil(@AlarmType int type, long triggerAtMillis, @Nullable String tag,
+ @NonNull OnAlarmListener listener, @Nullable Handler targetHandler) {
setImpl(type, triggerAtMillis, WINDOW_EXACT, 0, FLAG_IDLE_UNTIL, null,
listener, tag, targetHandler, null, null);
}
@@ -828,7 +879,7 @@
* @see Manifest.permission#SCHEDULE_EXACT_ALARM SCHEDULE_EXACT_ALARM
*/
@RequiresPermission(Manifest.permission.SCHEDULE_EXACT_ALARM)
- public void setAlarmClock(AlarmClockInfo info, PendingIntent operation) {
+ public void setAlarmClock(@NonNull AlarmClockInfo info, @NonNull PendingIntent operation) {
setImpl(RTC_WAKEUP, info.getTriggerTime(), WINDOW_EXACT, 0, 0, operation,
null, null, (Handler) null, null, info);
}
@@ -837,7 +888,8 @@
@SystemApi
@RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS)
public void set(@AlarmType int type, long triggerAtMillis, long windowMillis,
- long intervalMillis, PendingIntent operation, WorkSource workSource) {
+ long intervalMillis, @NonNull PendingIntent operation,
+ @Nullable WorkSource workSource) {
setImpl(type, triggerAtMillis, windowMillis, intervalMillis, 0, operation, null, null,
(Handler) null, workSource, null);
}
@@ -854,8 +906,8 @@
*/
@UnsupportedAppUsage
public void set(@AlarmType int type, long triggerAtMillis, long windowMillis,
- long intervalMillis, String tag, OnAlarmListener listener, Handler targetHandler,
- WorkSource workSource) {
+ long intervalMillis, @Nullable String tag, @NonNull OnAlarmListener listener,
+ @Nullable Handler targetHandler, @Nullable WorkSource workSource) {
setImpl(type, triggerAtMillis, windowMillis, intervalMillis, 0, null, listener, tag,
targetHandler, workSource, null);
}
@@ -873,8 +925,8 @@
@SystemApi
@RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS)
public void set(@AlarmType int type, long triggerAtMillis, long windowMillis,
- long intervalMillis, OnAlarmListener listener, Handler targetHandler,
- WorkSource workSource) {
+ long intervalMillis, @NonNull OnAlarmListener listener, @Nullable Handler targetHandler,
+ @Nullable WorkSource workSource) {
setImpl(type, triggerAtMillis, windowMillis, intervalMillis, 0, null, listener, null,
targetHandler, workSource, null);
}
@@ -1072,7 +1124,7 @@
* @see Intent#EXTRA_ALARM_COUNT
*/
public void setInexactRepeating(@AlarmType int type, long triggerAtMillis,
- long intervalMillis, PendingIntent operation) {
+ long intervalMillis, @NonNull PendingIntent operation) {
setImpl(type, triggerAtMillis, WINDOW_HEURISTIC, intervalMillis, 0, operation, null,
null, (Handler) null, null, null);
}
@@ -1122,7 +1174,7 @@
* @see #RTC_WAKEUP
*/
public void setAndAllowWhileIdle(@AlarmType int type, long triggerAtMillis,
- PendingIntent operation) {
+ @NonNull PendingIntent operation) {
setImpl(type, triggerAtMillis, WINDOW_HEURISTIC, 0, FLAG_ALLOW_WHILE_IDLE,
operation, null, null, (Handler) null, null, null);
}
@@ -1195,12 +1247,46 @@
*/
@RequiresPermission(value = Manifest.permission.SCHEDULE_EXACT_ALARM, conditional = true)
public void setExactAndAllowWhileIdle(@AlarmType int type, long triggerAtMillis,
- PendingIntent operation) {
+ @NonNull PendingIntent operation) {
setImpl(type, triggerAtMillis, WINDOW_EXACT, 0, FLAG_ALLOW_WHILE_IDLE, operation,
null, null, (Handler) null, null, null);
}
/**
+ * Like {@link #setExact(int, long, String, Executor, WorkSource, OnAlarmListener)}, but this
+ * alarm will be allowed to execute even when the system is in low-power idle modes.
+ *
+ * <p> See {@link #setExactAndAllowWhileIdle(int, long, PendingIntent)} for more details.
+ *
+ * @param type type of alarm
+ * @param triggerAtMillis The exact time in milliseconds, that the alarm should be delivered,
+ * expressed in the appropriate clock's units (depending on the alarm
+ * type).
+ * @param listener {@link OnAlarmListener} instance whose
+ * {@link OnAlarmListener#onAlarm() onAlarm()} method will be called when
+ * the alarm time is reached.
+ * @param executor The {@link Executor} on which to execute the listener's onAlarm()
+ * callback.
+ * @param tag Optional. A string tag used to identify this alarm in logs and
+ * battery-attribution.
+ * @param workSource A {@link WorkSource} object to attribute this alarm to the app that
+ * requested this work.
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(allOf = {
+ Manifest.permission.UPDATE_DEVICE_STATS,
+ Manifest.permission.SCHEDULE_EXACT_ALARM}, conditional = true)
+ public void setExactAndAllowWhileIdle(@AlarmType int type, long triggerAtMillis,
+ @Nullable String tag, @NonNull Executor executor, @Nullable WorkSource workSource,
+ @NonNull OnAlarmListener listener) {
+ Objects.requireNonNull(executor);
+ Objects.requireNonNull(listener);
+ setImpl(type, triggerAtMillis, WINDOW_EXACT, 0, FLAG_ALLOW_WHILE_IDLE, null, listener, tag,
+ executor, workSource, null);
+ }
+
+ /**
* Remove any alarms with a matching {@link Intent}.
* Any alarm, of any type, whose Intent matches this one (as defined by
* {@link Intent#filterEquals}), will be canceled.
@@ -1210,7 +1296,7 @@
*
* @see #set
*/
- public void cancel(PendingIntent operation) {
+ public void cancel(@NonNull PendingIntent operation) {
if (operation == null) {
final String msg = "cancel() called with a null PendingIntent";
if (mTargetSdkVersion >= Build.VERSION_CODES.N) {
@@ -1233,7 +1319,7 @@
*
* @param listener OnAlarmListener instance that is the target of a currently-set alarm.
*/
- public void cancel(OnAlarmListener listener) {
+ public void cancel(@NonNull OnAlarmListener listener) {
if (listener == null) {
throw new NullPointerException("cancel() called with a null OnAlarmListener");
}
diff --git a/apex/jobscheduler/framework/java/android/app/tare/EconomyManager.java b/apex/jobscheduler/framework/java/android/app/tare/EconomyManager.java
index 299ad66..4a3a6d9 100644
--- a/apex/jobscheduler/framework/java/android/app/tare/EconomyManager.java
+++ b/apex/jobscheduler/framework/java/android/app/tare/EconomyManager.java
@@ -113,7 +113,9 @@
/** @hide */
public static final String KEY_AM_INITIAL_CONSUMPTION_LIMIT = "am_initial_consumption_limit";
/** @hide */
- public static final String KEY_AM_HARD_CONSUMPTION_LIMIT = "am_hard_consumption_limit";
+ public static final String KEY_AM_MIN_CONSUMPTION_LIMIT = "am_minimum_consumption_limit";
+ /** @hide */
+ public static final String KEY_AM_MAX_CONSUMPTION_LIMIT = "am_maximum_consumption_limit";
// TODO: Add AlarmManager modifier keys
/** @hide */
public static final String KEY_AM_REWARD_TOP_ACTIVITY_INSTANT =
@@ -242,7 +244,9 @@
/** @hide */
public static final String KEY_JS_INITIAL_CONSUMPTION_LIMIT = "js_initial_consumption_limit";
/** @hide */
- public static final String KEY_JS_HARD_CONSUMPTION_LIMIT = "js_hard_consumption_limit";
+ public static final String KEY_JS_MIN_CONSUMPTION_LIMIT = "js_minimum_consumption_limit";
+ /** @hide */
+ public static final String KEY_JS_MAX_CONSUMPTION_LIMIT = "js_maximum_consumption_limit";
// TODO: Add JobScheduler modifier keys
/** @hide */
public static final String KEY_JS_REWARD_APP_INSTALL_INSTANT =
@@ -371,7 +375,9 @@
/** @hide */
public static final long DEFAULT_AM_INITIAL_CONSUMPTION_LIMIT_CAKES = arcToCake(2880);
/** @hide */
- public static final long DEFAULT_AM_HARD_CONSUMPTION_LIMIT_CAKES = arcToCake(15_000);
+ public static final long DEFAULT_AM_MIN_CONSUMPTION_LIMIT_CAKES = arcToCake(1440);
+ /** @hide */
+ public static final long DEFAULT_AM_MAX_CONSUMPTION_LIMIT_CAKES = arcToCake(15_000);
// TODO: add AlarmManager modifier default values
/** @hide */
public static final long DEFAULT_AM_REWARD_TOP_ACTIVITY_INSTANT_CAKES = arcToCake(0);
@@ -478,8 +484,10 @@
/** @hide */
public static final long DEFAULT_JS_INITIAL_CONSUMPTION_LIMIT_CAKES = arcToCake(29_000);
/** @hide */
- // TODO: set hard limit based on device type (phone vs tablet vs etc) + battery size
- public static final long DEFAULT_JS_HARD_CONSUMPTION_LIMIT_CAKES = arcToCake(250_000);
+ public static final long DEFAULT_JS_MIN_CONSUMPTION_LIMIT_CAKES = arcToCake(17_000);
+ /** @hide */
+ // TODO: set maximum limit based on device type (phone vs tablet vs etc) + battery size
+ public static final long DEFAULT_JS_MAX_CONSUMPTION_LIMIT_CAKES = arcToCake(250_000);
// TODO: add JobScheduler modifier default values
/** @hide */
public static final long DEFAULT_JS_REWARD_APP_INSTALL_INSTANT_CAKES = arcToCake(408);
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 6375d0d..d9fb318 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -432,6 +432,7 @@
break;
case Constants.KEY_MIN_LINEAR_BACKOFF_TIME_MS:
case Constants.KEY_MIN_EXP_BACKOFF_TIME_MS:
+ case Constants.KEY_SYSTEM_STOP_TO_FAILURE_RATIO:
mConstants.updateBackoffConstantsLocked();
break;
case Constants.KEY_CONN_CONGESTION_DELAY_FRAC:
@@ -509,6 +510,8 @@
private static final String KEY_MIN_LINEAR_BACKOFF_TIME_MS = "min_linear_backoff_time_ms";
private static final String KEY_MIN_EXP_BACKOFF_TIME_MS = "min_exp_backoff_time_ms";
+ private static final String KEY_SYSTEM_STOP_TO_FAILURE_RATIO =
+ "system_stop_to_failure_ratio";
private static final String KEY_CONN_CONGESTION_DELAY_FRAC = "conn_congestion_delay_frac";
private static final String KEY_CONN_PREFETCH_RELAX_FRAC = "conn_prefetch_relax_frac";
private static final String KEY_CONN_USE_CELL_SIGNAL_STRENGTH =
@@ -540,6 +543,7 @@
private static final float DEFAULT_MODERATE_USE_FACTOR = .5f;
private static final long DEFAULT_MIN_LINEAR_BACKOFF_TIME_MS = JobInfo.MIN_BACKOFF_MILLIS;
private static final long DEFAULT_MIN_EXP_BACKOFF_TIME_MS = JobInfo.MIN_BACKOFF_MILLIS;
+ private static final int DEFAULT_SYSTEM_STOP_TO_FAILURE_RATIO = 3;
private static final float DEFAULT_CONN_CONGESTION_DELAY_FRAC = 0.5f;
private static final float DEFAULT_CONN_PREFETCH_RELAX_FRAC = 0.5f;
private static final boolean DEFAULT_CONN_USE_CELL_SIGNAL_STRENGTH = true;
@@ -589,6 +593,11 @@
* The minimum backoff time to allow for exponential backoff.
*/
long MIN_EXP_BACKOFF_TIME_MS = DEFAULT_MIN_EXP_BACKOFF_TIME_MS;
+ /**
+ * The ratio to use to convert number of times a job was stopped by JobScheduler to an
+ * incremental failure in the backoff policy calculation.
+ */
+ int SYSTEM_STOP_TO_FAILURE_RATIO = DEFAULT_SYSTEM_STOP_TO_FAILURE_RATIO;
/**
* The fraction of a job's running window that must pass before we
@@ -700,6 +709,9 @@
MIN_EXP_BACKOFF_TIME_MS = DeviceConfig.getLong(DeviceConfig.NAMESPACE_JOB_SCHEDULER,
KEY_MIN_EXP_BACKOFF_TIME_MS,
DEFAULT_MIN_EXP_BACKOFF_TIME_MS);
+ SYSTEM_STOP_TO_FAILURE_RATIO = DeviceConfig.getInt(DeviceConfig.NAMESPACE_JOB_SCHEDULER,
+ KEY_SYSTEM_STOP_TO_FAILURE_RATIO,
+ DEFAULT_SYSTEM_STOP_TO_FAILURE_RATIO);
}
private void updateConnectivityConstantsLocked() {
@@ -797,6 +809,7 @@
pw.print(KEY_MIN_LINEAR_BACKOFF_TIME_MS, MIN_LINEAR_BACKOFF_TIME_MS).println();
pw.print(KEY_MIN_EXP_BACKOFF_TIME_MS, MIN_EXP_BACKOFF_TIME_MS).println();
+ pw.print(KEY_SYSTEM_STOP_TO_FAILURE_RATIO, SYSTEM_STOP_TO_FAILURE_RATIO).println();
pw.print(KEY_CONN_CONGESTION_DELAY_FRAC, CONN_CONGESTION_DELAY_FRAC).println();
pw.print(KEY_CONN_PREFETCH_RELAX_FRAC, CONN_PREFETCH_RELAX_FRAC).println();
pw.print(KEY_CONN_USE_CELL_SIGNAL_STRENGTH, CONN_USE_CELL_SIGNAL_STRENGTH).println();
@@ -1277,7 +1290,7 @@
jobStatus.getJob().isPrefetch(),
jobStatus.getJob().getPriority(),
jobStatus.getEffectivePriority(),
- jobStatus.getNumFailures());
+ jobStatus.getNumPreviousAttempts());
// 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
@@ -1476,7 +1489,7 @@
cancelled.getJob().isPrefetch(),
cancelled.getJob().getPriority(),
cancelled.getEffectivePriority(),
- cancelled.getNumFailures());
+ cancelled.getNumPreviousAttempts());
}
// If this is a replacement, bring in the new version of the job
if (incomingJob != null) {
@@ -1820,12 +1833,13 @@
Slog.wtf(TAG, "Not yet prepared when started tracking: " + jobStatus);
}
jobStatus.enqueueTime = sElapsedRealtimeClock.millis();
- final boolean update = mJobs.add(jobStatus);
+ final boolean update = lastJob != null;
+ mJobs.add(jobStatus);
if (mReadyToRock) {
for (int i = 0; i < mControllers.size(); i++) {
StateController controller = mControllers.get(i);
if (update) {
- controller.maybeStopTrackingJobLocked(jobStatus, null, true);
+ controller.maybeStopTrackingJobLocked(jobStatus, null);
}
controller.maybeStartTrackingJobLocked(jobStatus, lastJob);
}
@@ -1858,7 +1872,7 @@
if (mReadyToRock) {
for (int i = 0; i < mControllers.size(); i++) {
StateController controller = mControllers.get(i);
- controller.maybeStopTrackingJobLocked(jobStatus, incomingJob, false);
+ controller.maybeStopTrackingJobLocked(jobStatus, incomingJob);
}
}
return removed;
@@ -1903,7 +1917,7 @@
* Reschedules the given job based on the job's backoff policy. It doesn't make sense to
* specify an override deadline on a failed job (the failed job will run even though it's not
* ready), so we reschedule it with {@link JobStatus#NO_LATEST_RUNTIME}, but specify that any
- * ready job with {@link JobStatus#getNumFailures()} > 0 will be executed.
+ * ready job with {@link JobStatus#getNumPreviousAttempts()} > 0 will be executed.
*
* @param failureToReschedule Provided job status that we will reschedule.
* @return A newly instantiated JobStatus with the same constraints as the last job except
@@ -1911,12 +1925,24 @@
* @see #maybeQueueReadyJobsForExecutionLocked
*/
@VisibleForTesting
- JobStatus getRescheduleJobForFailureLocked(JobStatus failureToReschedule) {
+ JobStatus getRescheduleJobForFailureLocked(JobStatus failureToReschedule,
+ int internalStopReason) {
final long elapsedNowMillis = sElapsedRealtimeClock.millis();
final JobInfo job = failureToReschedule.getJob();
final long initialBackoffMillis = job.getInitialBackoffMillis();
- final int backoffAttempts = failureToReschedule.getNumFailures() + 1;
+ int numFailures = failureToReschedule.getNumFailures();
+ int numSystemStops = failureToReschedule.getNumSystemStops();
+ // We should back off slowly if JobScheduler keeps stopping the job,
+ // but back off immediately if the issue appeared to be the app's fault.
+ if (internalStopReason == JobParameters.INTERNAL_STOP_REASON_SUCCESSFUL_FINISH
+ || internalStopReason == JobParameters.INTERNAL_STOP_REASON_TIMEOUT) {
+ numFailures++;
+ } else {
+ numSystemStops++;
+ }
+ final int backoffAttempts = Math.max(1,
+ numFailures + numSystemStops / mConstants.SYSTEM_STOP_TO_FAILURE_RATIO);
long delayMillis;
switch (job.getBackoffPolicy()) {
@@ -1943,7 +1969,7 @@
Math.min(delayMillis, JobInfo.MAX_BACKOFF_DELAY_MILLIS);
JobStatus newJob = new JobStatus(failureToReschedule,
elapsedNowMillis + delayMillis,
- JobStatus.NO_LATEST_RUNTIME, backoffAttempts,
+ JobStatus.NO_LATEST_RUNTIME, numFailures, numSystemStops,
failureToReschedule.getLastSuccessfulRunTime(), sSystemClock.millis());
if (job.isPeriodic()) {
newJob.setOriginalLatestRunTimeElapsed(
@@ -2034,7 +2060,7 @@
+ newLatestRuntimeElapsed);
return new JobStatus(periodicToReschedule,
elapsedNow + period - flex, elapsedNow + period,
- 0 /* backoffAttempt */,
+ 0 /* numFailures */, 0 /* numSystemStops */,
sSystemClock.millis() /* lastSuccessfulRunTime */,
periodicToReschedule.getLastFailedRunTime());
}
@@ -2049,7 +2075,7 @@
}
return new JobStatus(periodicToReschedule,
newEarliestRunTimeElapsed, newLatestRuntimeElapsed,
- 0 /* backoffAttempt */,
+ 0 /* numFailures */, 0 /* numSystemStops */,
sSystemClock.millis() /* lastSuccessfulRunTime */,
periodicToReschedule.getLastFailedRunTime());
}
@@ -2093,7 +2119,7 @@
// job so we can transfer any appropriate state over from the previous job when
// we stop it.
final JobStatus rescheduledJob = needsReschedule
- ? getRescheduleJobForFailureLocked(jobStatus) : null;
+ ? getRescheduleJobForFailureLocked(jobStatus, debugStopReason) : null;
if (rescheduledJob != null
&& (debugStopReason == JobParameters.INTERNAL_STOP_REASON_TIMEOUT
|| debugStopReason == JobParameters.INTERNAL_STOP_REASON_PREEMPT)) {
@@ -2427,7 +2453,7 @@
shouldForceBatchJob =
mPrefetchController.getNextEstimatedLaunchTimeLocked(job)
> relativelySoonCutoffTime;
- } else if (job.getNumFailures() > 0) {
+ } else if (job.getNumPreviousAttempts() > 0) {
shouldForceBatchJob = false;
} else {
final long nowElapsed = sElapsedRealtimeClock.millis();
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 d6456f0..9e3f19d 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobServiceContext.java
@@ -363,7 +363,7 @@
job.getJob().isPrefetch(),
job.getJob().getPriority(),
job.getEffectivePriority(),
- job.getNumFailures());
+ job.getNumPreviousAttempts());
if (Trace.isTagEnabled(Trace.TRACE_TAG_SYSTEM_SERVER)) {
// Use the context's ID to distinguish traces since there'll only be one job
// running per context.
@@ -1032,7 +1032,7 @@
completedJob.getJob().isPrefetch(),
completedJob.getJob().getPriority(),
completedJob.getEffectivePriority(),
- completedJob.getNumFailures());
+ completedJob.getNumPreviousAttempts());
if (Trace.isTagEnabled(Trace.TRACE_TAG_SYSTEM_SERVER)) {
Trace.asyncTraceForTrackEnd(Trace.TRACE_TAG_SYSTEM_SERVER, "JobScheduler",
completedJob.getTag(), getId());
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobStore.java b/apex/jobscheduler/service/java/com/android/server/job/JobStore.java
index 22b0968..68cb049 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobStore.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobStore.java
@@ -194,7 +194,7 @@
convertRtcBoundsToElapsed(utcTimes, elapsedNow);
JobStatus newJob = new JobStatus(job,
elapsedRuntimes.first, elapsedRuntimes.second,
- 0, job.getLastSuccessfulRunTime(), job.getLastFailedRunTime());
+ 0, 0, job.getLastSuccessfulRunTime(), job.getLastFailedRunTime());
newJob.prepareLocked();
toAdd.add(newJob);
toRemove.add(job);
@@ -203,13 +203,12 @@
}
/**
- * Add a job to the master list, persisting it if necessary. If the JobStatus already exists,
- * it will be replaced.
+ * Add a job to the master list, persisting it if necessary.
+ * Similar jobs to the new job will not be removed.
+ *
* @param jobStatus Job to add.
- * @return Whether or not an equivalent JobStatus was replaced by this operation.
*/
- public boolean add(JobStatus jobStatus) {
- boolean replaced = mJobSet.remove(jobStatus);
+ public void add(JobStatus jobStatus) {
mJobSet.add(jobStatus);
if (jobStatus.isPersisted()) {
maybeWriteStatusToDiskAsync();
@@ -217,7 +216,6 @@
if (DEBUG) {
Slog.d(TAG, "Added job status to store: " + jobStatus);
}
- return replaced;
}
/**
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/BackgroundJobsController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/BackgroundJobsController.java
index 65d7121..ecee10a 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/BackgroundJobsController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/BackgroundJobsController.java
@@ -81,8 +81,7 @@
}
@Override
- public void maybeStopTrackingJobLocked(JobStatus jobStatus, JobStatus incomingJob,
- boolean forUpdate) {
+ public void maybeStopTrackingJobLocked(JobStatus jobStatus, JobStatus incomingJob) {
}
@Override
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/BatteryController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/BatteryController.java
index d284a99..2ca3f8f 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/BatteryController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/BatteryController.java
@@ -133,7 +133,7 @@
}
@Override
- public void maybeStopTrackingJobLocked(JobStatus taskStatus, JobStatus incomingJob, boolean forUpdate) {
+ public void maybeStopTrackingJobLocked(JobStatus taskStatus, JobStatus incomingJob) {
if (taskStatus.clearTrackingController(JobStatus.TRACKING_BATTERY)) {
mTrackedTasks.remove(taskStatus);
mTopStartedJobs.remove(taskStatus);
@@ -143,7 +143,7 @@
@Override
public void stopTrackingRestrictedJobLocked(JobStatus jobStatus) {
if (!jobStatus.hasPowerConstraint()) {
- maybeStopTrackingJobLocked(jobStatus, null, false);
+ maybeStopTrackingJobLocked(jobStatus, null);
}
}
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/ComponentController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/ComponentController.java
index 9b59560..b029e00 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/ComponentController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/ComponentController.java
@@ -127,8 +127,7 @@
}
@Override
- public void maybeStopTrackingJobLocked(JobStatus jobStatus, JobStatus incomingJob,
- boolean forUpdate) {
+ public void maybeStopTrackingJobLocked(JobStatus jobStatus, JobStatus incomingJob) {
}
@Override
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java
index d2dc2a7e..16dd1672 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java
@@ -290,8 +290,7 @@
@GuardedBy("mLock")
@Override
- public void maybeStopTrackingJobLocked(JobStatus jobStatus, JobStatus incomingJob,
- boolean forUpdate) {
+ public void maybeStopTrackingJobLocked(JobStatus jobStatus, JobStatus incomingJob) {
if (jobStatus.clearTrackingController(JobStatus.TRACKING_CONNECTIVITY)) {
ArraySet<JobStatus> jobs = mTrackedJobs.get(jobStatus.getSourceUid());
if (jobs != null) {
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/ContentObserverController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/ContentObserverController.java
index 83a756c..847a1bf 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/ContentObserverController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/ContentObserverController.java
@@ -159,8 +159,7 @@
}
@Override
- public void maybeStopTrackingJobLocked(JobStatus taskStatus, JobStatus incomingJob,
- boolean forUpdate) {
+ public void maybeStopTrackingJobLocked(JobStatus taskStatus, JobStatus incomingJob) {
if (taskStatus.clearTrackingController(JobStatus.TRACKING_CONTENT)) {
mTrackedTasks.remove(taskStatus);
if (taskStatus.contentObserverJobInstance != null) {
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/DeviceIdleJobsController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/DeviceIdleJobsController.java
index abbe177..bdf72b6 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/DeviceIdleJobsController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/DeviceIdleJobsController.java
@@ -225,8 +225,7 @@
}
@Override
- public void maybeStopTrackingJobLocked(JobStatus jobStatus, JobStatus incomingJob,
- boolean forUpdate) {
+ public void maybeStopTrackingJobLocked(JobStatus jobStatus, JobStatus incomingJob) {
if ((jobStatus.getFlags()&JobInfo.FLAG_IMPORTANT_WHILE_FOREGROUND) != 0) {
mAllowInIdleJobs.remove(jobStatus);
}
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/FlexibilityController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/FlexibilityController.java
index 547f94ba..4c17692 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/FlexibilityController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/FlexibilityController.java
@@ -213,7 +213,7 @@
@Override
@GuardedBy("mLock")
- public void maybeStopTrackingJobLocked(JobStatus js, JobStatus incomingJob, boolean forUpdate) {
+ public void maybeStopTrackingJobLocked(JobStatus js, JobStatus incomingJob) {
if (js.clearTrackingController(JobStatus.TRACKING_FLEXIBILITY)) {
mFlexibilityAlarmQueue.removeAlarmForKey(js);
mFlexibilityTracker.remove(js);
@@ -342,10 +342,10 @@
// There is no deadline and no estimated launch time.
return NO_LIFECYCLE_END;
}
- if (js.getNumFailures() > 1) {
- // Number of failures will not equal one as per restriction in JobStatus constructor.
+ // Increase the flex deadline for jobs rescheduled more than once.
+ if (js.getNumPreviousAttempts() > 1) {
return earliest + Math.min(
- (long) Math.scalb(mRescheduledJobDeadline, js.getNumFailures() - 2),
+ (long) Math.scalb(mRescheduledJobDeadline, js.getNumPreviousAttempts() - 2),
mMaxRescheduledDeadline);
}
return js.getLatestRunTimeElapsed() == JobStatus.NO_LATEST_RUNTIME
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/IdleController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/IdleController.java
index 926cfc1..a25af71 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/IdleController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/IdleController.java
@@ -76,8 +76,7 @@
}
@Override
- public void maybeStopTrackingJobLocked(JobStatus taskStatus, JobStatus incomingJob,
- boolean forUpdate) {
+ public void maybeStopTrackingJobLocked(JobStatus taskStatus, JobStatus incomingJob) {
if (taskStatus.clearTrackingController(JobStatus.TRACKING_IDLE)) {
mTrackedTasks.remove(taskStatus);
}
@@ -86,7 +85,7 @@
@Override
public void stopTrackingRestrictedJobLocked(JobStatus jobStatus) {
if (!jobStatus.hasIdleConstraint()) {
- maybeStopTrackingJobLocked(jobStatus, null, false);
+ maybeStopTrackingJobLocked(jobStatus, null);
}
}
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 de602a8..f9fb0d0 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
@@ -241,10 +241,22 @@
*/
private long mOriginalLatestRunTimeElapsedMillis;
- /** How many times this job has failed, used to compute back-off. */
+ /**
+ * How many times this job has failed to complete on its own
+ * (via {@link android.app.job.JobService#jobFinished(JobParameters, boolean)} or because of
+ * a timeout).
+ * This count doesn't include most times JobScheduler decided to stop the job
+ * (via {@link android.app.job.JobService#onStopJob(JobParameters)}.
+ */
private final int numFailures;
/**
+ * The number of times JobScheduler has forced this job to stop due to reasons mostly outside
+ * of the app's control.
+ */
+ private final int mNumSystemStops;
+
+ /**
* Which app standby bucket this job's app is in. Updated when the app is moved to a
* different bucket.
*/
@@ -488,6 +500,8 @@
* @param tag A string associated with the job for debugging/logging purposes.
* @param numFailures Count of how many times this job has requested a reschedule because
* its work was not yet finished.
+ * @param numSystemStops Count of how many times JobScheduler has forced this job to stop due to
+ * factors mostly out of the app's control.
* @param earliestRunTimeElapsedMillis Milestone: earliest point in time at which the job
* is to be considered runnable
* @param latestRunTimeElapsedMillis Milestone: point in time at which the job will be
@@ -497,7 +511,7 @@
* @param internalFlags Non-API property flags about this job
*/
private JobStatus(JobInfo job, int callingUid, String sourcePackageName,
- int sourceUserId, int standbyBucket, String tag, int numFailures,
+ int sourceUserId, int standbyBucket, String tag, int numFailures, int numSystemStops,
long earliestRunTimeElapsedMillis, long latestRunTimeElapsedMillis,
long lastSuccessfulRunTime, long lastFailedRunTime, int internalFlags,
int dynamicConstraints) {
@@ -535,6 +549,7 @@
this.latestRunTimeElapsedMillis = latestRunTimeElapsedMillis;
this.mOriginalLatestRunTimeElapsedMillis = latestRunTimeElapsedMillis;
this.numFailures = numFailures;
+ mNumSystemStops = numSystemStops;
int requiredConstraints = job.getConstraintFlags();
if (job.getRequiredNetwork() != null) {
@@ -576,7 +591,7 @@
// Otherwise, every consecutive reschedule increases a jobs' flexibility deadline.
if (!isRequestedExpeditedJob()
&& satisfiesMinWindowException
- && numFailures != 1
+ && (numFailures + numSystemStops) != 1
&& lacksSomeFlexibleConstraints) {
mNumRequiredFlexibleConstraints =
NUM_SYSTEM_WIDE_FLEXIBLE_CONSTRAINTS + (mPreferUnmetered ? 1 : 0);
@@ -626,7 +641,7 @@
this(jobStatus.getJob(), jobStatus.getUid(),
jobStatus.getSourcePackageName(), jobStatus.getSourceUserId(),
jobStatus.getStandbyBucket(),
- jobStatus.getSourceTag(), jobStatus.getNumFailures(),
+ jobStatus.getSourceTag(), jobStatus.getNumFailures(), jobStatus.getNumSystemStops(),
jobStatus.getEarliestRunTime(), jobStatus.getLatestRunTimeElapsed(),
jobStatus.getLastSuccessfulRunTime(), jobStatus.getLastFailedRunTime(),
jobStatus.getInternalFlags(), jobStatus.mDynamicConstraints);
@@ -654,7 +669,7 @@
int innerFlags, int dynamicConstraints) {
this(job, callingUid, sourcePkgName, sourceUserId,
standbyBucket,
- sourceTag, 0,
+ sourceTag, /* numFailures */ 0, /* numSystemStops */ 0,
earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis,
lastSuccessfulRunTime, lastFailedRunTime, innerFlags, dynamicConstraints);
@@ -673,12 +688,13 @@
/** Create a new job to be rescheduled with the provided parameters. */
public JobStatus(JobStatus rescheduling,
long newEarliestRuntimeElapsedMillis,
- long newLatestRuntimeElapsedMillis, int backoffAttempt,
+ long newLatestRuntimeElapsedMillis, int numFailures, int numSystemStops,
long lastSuccessfulRunTime, long lastFailedRunTime) {
this(rescheduling.job, rescheduling.getUid(),
rescheduling.getSourcePackageName(), rescheduling.getSourceUserId(),
rescheduling.getStandbyBucket(),
- rescheduling.getSourceTag(), backoffAttempt, newEarliestRuntimeElapsedMillis,
+ rescheduling.getSourceTag(), numFailures, numSystemStops,
+ newEarliestRuntimeElapsedMillis,
newLatestRuntimeElapsedMillis,
lastSuccessfulRunTime, lastFailedRunTime, rescheduling.getInternalFlags(),
rescheduling.mDynamicConstraints);
@@ -715,7 +731,7 @@
int standbyBucket = JobSchedulerService.standbyBucketForPackage(jobPackage,
sourceUserId, elapsedNow);
return new JobStatus(job, callingUid, sourcePkg, sourceUserId,
- standbyBucket, tag, 0,
+ standbyBucket, tag, /* numFailures */ 0, /* numSystemStops */ 0,
earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis,
0 /* lastSuccessfulRunTime */, 0 /* lastFailedRunTime */,
/*innerFlags=*/ 0, /* dynamicConstraints */ 0);
@@ -868,10 +884,27 @@
pw.print(job.getId());
}
+ /**
+ * Returns the number of times the job stopped previously for reasons that appeared to be within
+ * the app's control.
+ */
public int getNumFailures() {
return numFailures;
}
+ /**
+ * Returns the number of times the system stopped a previous execution of this job for reasons
+ * that were likely outside the app's control.
+ */
+ public int getNumSystemStops() {
+ return mNumSystemStops;
+ }
+
+ /** Returns the total number of times we've attempted to run this job in the past. */
+ public int getNumPreviousAttempts() {
+ return numFailures + mNumSystemStops;
+ }
+
public ComponentName getServiceComponent() {
return job.getService();
}
@@ -1857,6 +1890,10 @@
sb.append(" failures=");
sb.append(numFailures);
}
+ if (mNumSystemStops != 0) {
+ sb.append(" system stops=");
+ sb.append(mNumSystemStops);
+ }
if (isReady()) {
sb.append(" READY");
} else {
@@ -2382,6 +2419,9 @@
if (numFailures != 0) {
pw.print("Num failures: "); pw.println(numFailures);
}
+ if (mNumSystemStops != 0) {
+ pw.print("Num system stops: "); pw.println(mNumSystemStops);
+ }
if (mLastSuccessfulRunTime != 0) {
pw.print("Last successful run: ");
pw.println(formatTime(mLastSuccessfulRunTime));
@@ -2579,7 +2619,7 @@
proto.write(JobStatusDumpProto.ORIGINAL_LATEST_RUNTIME_ELAPSED,
mOriginalLatestRunTimeElapsedMillis);
- proto.write(JobStatusDumpProto.NUM_FAILURES, numFailures);
+ proto.write(JobStatusDumpProto.NUM_FAILURES, numFailures + mNumSystemStops);
proto.write(JobStatusDumpProto.LAST_SUCCESSFUL_RUN_TIME, mLastSuccessfulRunTime);
proto.write(JobStatusDumpProto.LAST_FAILED_RUN_TIME, mLastFailedRunTime);
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/PrefetchController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/PrefetchController.java
index 2a66643..c46ffd7 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/PrefetchController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/PrefetchController.java
@@ -167,8 +167,7 @@
@Override
@GuardedBy("mLock")
- public void maybeStopTrackingJobLocked(JobStatus jobStatus, JobStatus incomingJob,
- boolean forUpdate) {
+ public void maybeStopTrackingJobLocked(JobStatus jobStatus, JobStatus incomingJob) {
final int userId = jobStatus.getSourceUserId();
final String pkgName = jobStatus.getSourcePackageName();
final ArraySet<JobStatus> jobs = mTrackedJobs.get(userId, pkgName);
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
index 873fb77..d8206ad 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/QuotaController.java
@@ -673,8 +673,7 @@
@Override
@GuardedBy("mLock")
- public void maybeStopTrackingJobLocked(JobStatus jobStatus, JobStatus incomingJob,
- boolean forUpdate) {
+ public void maybeStopTrackingJobLocked(JobStatus jobStatus, JobStatus incomingJob) {
if (jobStatus.clearTrackingController(JobStatus.TRACKING_QUOTA)) {
unprepareFromExecutionLocked(jobStatus);
final int userId = jobStatus.getSourceUserId();
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/StateController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/StateController.java
index 8c6ce95..44ac798 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/StateController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/StateController.java
@@ -85,8 +85,7 @@
/**
* Remove task - this will happen if the task is cancelled, completed, etc.
*/
- public abstract void maybeStopTrackingJobLocked(JobStatus jobStatus, JobStatus incomingJob,
- boolean forUpdate);
+ public abstract void maybeStopTrackingJobLocked(JobStatus jobStatus, JobStatus incomingJob);
/**
* Called when a new job is being created to reschedule an old failed job.
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/StorageController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/StorageController.java
index 1ce0a7f6..11e2ff7 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/StorageController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/StorageController.java
@@ -70,8 +70,7 @@
}
@Override
- public void maybeStopTrackingJobLocked(JobStatus taskStatus, JobStatus incomingJob,
- boolean forUpdate) {
+ public void maybeStopTrackingJobLocked(JobStatus taskStatus, JobStatus incomingJob) {
if (taskStatus.clearTrackingController(JobStatus.TRACKING_STORAGE)) {
mTrackedTasks.remove(taskStatus);
}
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/TareController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/TareController.java
index b2ca3a0..cafb02d 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/TareController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/TareController.java
@@ -383,8 +383,7 @@
@Override
@GuardedBy("mLock")
- public void maybeStopTrackingJobLocked(JobStatus jobStatus, JobStatus incomingJob,
- boolean forUpdate) {
+ public void maybeStopTrackingJobLocked(JobStatus jobStatus, JobStatus incomingJob) {
final int userId = jobStatus.getSourceUserId();
final String pkgName = jobStatus.getSourcePackageName();
if (!mTopStartedJobs.remove(jobStatus) && jobStatus.madeActive > 0) {
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/TimeController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/TimeController.java
index b6361ce..5195f28 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/TimeController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/TimeController.java
@@ -79,7 +79,7 @@
@Override
public void maybeStartTrackingJobLocked(JobStatus job, JobStatus lastJob) {
if (job.hasTimingDelayConstraint() || job.hasDeadlineConstraint()) {
- maybeStopTrackingJobLocked(job, null, false);
+ maybeStopTrackingJobLocked(job, null);
// First: check the constraints now, because if they are already satisfied
// then there is no need to track it. This gives us a fast path for a common
@@ -134,8 +134,7 @@
* tracking was the one our alarms were based off of.
*/
@Override
- public void maybeStopTrackingJobLocked(JobStatus job, JobStatus incomingJob,
- boolean forUpdate) {
+ public void maybeStopTrackingJobLocked(JobStatus job, JobStatus incomingJob) {
if (job.clearTrackingController(JobStatus.TRACKING_TIME)) {
if (mTrackedJobs.remove(job)) {
checkExpiredDelaysAndResetAlarm();
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/AlarmManagerEconomicPolicy.java b/apex/jobscheduler/service/java/com/android/server/tare/AlarmManagerEconomicPolicy.java
index b426f16..46338fa 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/AlarmManagerEconomicPolicy.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/AlarmManagerEconomicPolicy.java
@@ -33,9 +33,10 @@
import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_INEXACT_NONWAKEUP_CTP_CAKES;
import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_INEXACT_WAKEUP_BASE_PRICE_CAKES;
import static android.app.tare.EconomyManager.DEFAULT_AM_ACTION_ALARM_INEXACT_WAKEUP_CTP_CAKES;
-import static android.app.tare.EconomyManager.DEFAULT_AM_HARD_CONSUMPTION_LIMIT_CAKES;
import static android.app.tare.EconomyManager.DEFAULT_AM_INITIAL_CONSUMPTION_LIMIT_CAKES;
+import static android.app.tare.EconomyManager.DEFAULT_AM_MAX_CONSUMPTION_LIMIT_CAKES;
import static android.app.tare.EconomyManager.DEFAULT_AM_MAX_SATIATED_BALANCE_CAKES;
+import static android.app.tare.EconomyManager.DEFAULT_AM_MIN_CONSUMPTION_LIMIT_CAKES;
import static android.app.tare.EconomyManager.DEFAULT_AM_MIN_SATIATED_BALANCE_EXEMPTED_CAKES;
import static android.app.tare.EconomyManager.DEFAULT_AM_MIN_SATIATED_BALANCE_OTHER_APP_CAKES;
import static android.app.tare.EconomyManager.DEFAULT_AM_REWARD_NOTIFICATION_INTERACTION_INSTANT_CAKES;
@@ -71,9 +72,10 @@
import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_INEXACT_NONWAKEUP_CTP;
import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_INEXACT_WAKEUP_BASE_PRICE;
import static android.app.tare.EconomyManager.KEY_AM_ACTION_ALARM_INEXACT_WAKEUP_CTP;
-import static android.app.tare.EconomyManager.KEY_AM_HARD_CONSUMPTION_LIMIT;
import static android.app.tare.EconomyManager.KEY_AM_INITIAL_CONSUMPTION_LIMIT;
+import static android.app.tare.EconomyManager.KEY_AM_MAX_CONSUMPTION_LIMIT;
import static android.app.tare.EconomyManager.KEY_AM_MAX_SATIATED_BALANCE;
+import static android.app.tare.EconomyManager.KEY_AM_MIN_CONSUMPTION_LIMIT;
import static android.app.tare.EconomyManager.KEY_AM_MIN_SATIATED_BALANCE_EXEMPTED;
import static android.app.tare.EconomyManager.KEY_AM_MIN_SATIATED_BALANCE_OTHER_APP;
import static android.app.tare.EconomyManager.KEY_AM_REWARD_NOTIFICATION_INTERACTION_INSTANT;
@@ -146,7 +148,8 @@
private long mMinSatiatedBalanceOther;
private long mMaxSatiatedBalance;
private long mInitialSatiatedConsumptionLimit;
- private long mHardSatiatedConsumptionLimit;
+ private long mMinSatiatedConsumptionLimit;
+ private long mMaxSatiatedConsumptionLimit;
private final KeyValueListParser mParser = new KeyValueListParser(',');
private final Injector mInjector;
@@ -199,8 +202,13 @@
}
@Override
- long getHardSatiatedConsumptionLimit() {
- return mHardSatiatedConsumptionLimit;
+ long getMinSatiatedConsumptionLimit() {
+ return mMinSatiatedConsumptionLimit;
+ }
+
+ @Override
+ long getMaxSatiatedConsumptionLimit() {
+ return mMaxSatiatedConsumptionLimit;
}
@NonNull
@@ -240,12 +248,15 @@
mMaxSatiatedBalance = getConstantAsCake(mParser, properties,
KEY_AM_MAX_SATIATED_BALANCE, DEFAULT_AM_MAX_SATIATED_BALANCE_CAKES,
Math.max(arcToCake(1), mMinSatiatedBalanceExempted));
+ mMinSatiatedConsumptionLimit = getConstantAsCake(mParser, properties,
+ KEY_AM_MIN_CONSUMPTION_LIMIT, DEFAULT_AM_MIN_CONSUMPTION_LIMIT_CAKES,
+ arcToCake(1));
mInitialSatiatedConsumptionLimit = getConstantAsCake(mParser, properties,
- KEY_AM_INITIAL_CONSUMPTION_LIMIT, DEFAULT_AM_INITIAL_CONSUMPTION_LIMIT_CAKES,
- arcToCake(1));
- mHardSatiatedConsumptionLimit = getConstantAsCake(mParser, properties,
- KEY_AM_HARD_CONSUMPTION_LIMIT, DEFAULT_AM_HARD_CONSUMPTION_LIMIT_CAKES,
- mInitialSatiatedConsumptionLimit);
+ KEY_AM_INITIAL_CONSUMPTION_LIMIT, DEFAULT_AM_INITIAL_CONSUMPTION_LIMIT_CAKES,
+ mMinSatiatedConsumptionLimit);
+ mMaxSatiatedConsumptionLimit = getConstantAsCake(mParser, properties,
+ KEY_AM_MAX_CONSUMPTION_LIMIT, DEFAULT_AM_MAX_CONSUMPTION_LIMIT_CAKES,
+ mInitialSatiatedConsumptionLimit);
final long exactAllowWhileIdleWakeupBasePrice = getConstantAsCake(mParser, properties,
KEY_AM_ACTION_ALARM_ALLOW_WHILE_IDLE_EXACT_WAKEUP_BASE_PRICE,
@@ -396,9 +407,11 @@
pw.decreaseIndent();
pw.print("Max satiated balance", cakeToString(mMaxSatiatedBalance)).println();
pw.print("Consumption limits: [");
+ pw.print(cakeToString(mMinSatiatedConsumptionLimit));
+ pw.print(", ");
pw.print(cakeToString(mInitialSatiatedConsumptionLimit));
pw.print(", ");
- pw.print(cakeToString(mHardSatiatedConsumptionLimit));
+ pw.print(cakeToString(mMaxSatiatedConsumptionLimit));
pw.println("]");
pw.println();
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/CompleteEconomicPolicy.java b/apex/jobscheduler/service/java/com/android/server/tare/CompleteEconomicPolicy.java
index 66f7c35..7a96076 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/CompleteEconomicPolicy.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/CompleteEconomicPolicy.java
@@ -43,7 +43,8 @@
private int mEnabledEconomicPolicyIds = 0;
private int[] mCostModifiers = EmptyArray.INT;
private long mInitialConsumptionLimit;
- private long mHardConsumptionLimit;
+ private long mMinConsumptionLimit;
+ private long mMaxConsumptionLimit;
CompleteEconomicPolicy(@NonNull InternalResourceService irs) {
this(irs, new CompleteInjector());
@@ -100,14 +101,17 @@
private void updateLimits() {
long initialConsumptionLimit = 0;
- long hardConsumptionLimit = 0;
+ long minConsumptionLimit = 0;
+ long maxConsumptionLimit = 0;
for (int i = 0; i < mEnabledEconomicPolicies.size(); ++i) {
final EconomicPolicy economicPolicy = mEnabledEconomicPolicies.valueAt(i);
initialConsumptionLimit += economicPolicy.getInitialSatiatedConsumptionLimit();
- hardConsumptionLimit += economicPolicy.getHardSatiatedConsumptionLimit();
+ minConsumptionLimit += economicPolicy.getMinSatiatedConsumptionLimit();
+ maxConsumptionLimit += economicPolicy.getMaxSatiatedConsumptionLimit();
}
mInitialConsumptionLimit = initialConsumptionLimit;
- mHardConsumptionLimit = hardConsumptionLimit;
+ mMinConsumptionLimit = minConsumptionLimit;
+ mMaxConsumptionLimit = maxConsumptionLimit;
}
@Override
@@ -134,8 +138,13 @@
}
@Override
- long getHardSatiatedConsumptionLimit() {
- return mHardConsumptionLimit;
+ long getMinSatiatedConsumptionLimit() {
+ return mMinConsumptionLimit;
+ }
+
+ @Override
+ long getMaxSatiatedConsumptionLimit() {
+ return mMaxConsumptionLimit;
}
@NonNull
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/EconomicPolicy.java b/apex/jobscheduler/service/java/com/android/server/tare/EconomicPolicy.java
index 008dcb8..b52f6f1 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/EconomicPolicy.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/EconomicPolicy.java
@@ -232,15 +232,21 @@
* Returns the maximum number of cakes that should be consumed during a full 100% discharge
* cycle. This is the initial limit. The system may choose to increase the limit over time,
* but the increased limit should never exceed the value returned from
- * {@link #getHardSatiatedConsumptionLimit()}.
+ * {@link #getMaxSatiatedConsumptionLimit()}.
*/
abstract long getInitialSatiatedConsumptionLimit();
/**
- * Returns the maximum number of cakes that should be consumed during a full 100% discharge
- * cycle. This is the hard limit that should never be exceeded.
+ * Returns the minimum number of cakes that should be available for consumption during a full
+ * 100% discharge cycle.
*/
- abstract long getHardSatiatedConsumptionLimit();
+ abstract long getMinSatiatedConsumptionLimit();
+
+ /**
+ * Returns the maximum number of cakes that should be available for consumption during a full
+ * 100% discharge cycle.
+ */
+ abstract long getMaxSatiatedConsumptionLimit();
/** Return the set of modifiers that should apply to this policy's costs. */
@NonNull
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java b/apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java
index dd0a194..581a545 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java
@@ -670,7 +670,7 @@
final long shortfall = (mCurrentBatteryLevel - QUANTITATIVE_EASING_BATTERY_THRESHOLD)
* currentConsumptionLimit / 100;
final long newConsumptionLimit = Math.min(currentConsumptionLimit + shortfall,
- mCompleteEconomicPolicy.getHardSatiatedConsumptionLimit());
+ mCompleteEconomicPolicy.getMaxSatiatedConsumptionLimit());
if (newConsumptionLimit != currentConsumptionLimit) {
Slog.i(TAG, "Increasing consumption limit from " + cakeToString(currentConsumptionLimit)
+ " to " + cakeToString(newConsumptionLimit));
@@ -720,12 +720,12 @@
// The stock is too low. We're doing pretty well. We can increase the stock slightly
// to let apps do more work in the background.
newConsumptionLimit = Math.min((long) (currentConsumptionLimit * 1.01),
- mCompleteEconomicPolicy.getHardSatiatedConsumptionLimit());
+ mCompleteEconomicPolicy.getMaxSatiatedConsumptionLimit());
} else if (percentageOfTarget < 100) {
// The stock is too high IMO. We're below the target. Decrease the stock to reduce
// background work.
newConsumptionLimit = Math.max((long) (currentConsumptionLimit * .98),
- mCompleteEconomicPolicy.getInitialSatiatedConsumptionLimit());
+ mCompleteEconomicPolicy.getMinSatiatedConsumptionLimit());
} else {
// The stock is just right.
return;
@@ -957,9 +957,9 @@
} else {
mScribe.loadFromDiskLocked();
if (mScribe.getSatiatedConsumptionLimitLocked()
- < mCompleteEconomicPolicy.getInitialSatiatedConsumptionLimit()
+ < mCompleteEconomicPolicy.getMinSatiatedConsumptionLimit()
|| mScribe.getSatiatedConsumptionLimitLocked()
- > mCompleteEconomicPolicy.getHardSatiatedConsumptionLimit()) {
+ > mCompleteEconomicPolicy.getMaxSatiatedConsumptionLimit()) {
// Reset the consumption limit since several factors may have changed.
mScribe.setConsumptionLimitLocked(
mCompleteEconomicPolicy.getInitialSatiatedConsumptionLimit());
@@ -1442,17 +1442,16 @@
private void updateEconomicPolicy() {
synchronized (mLock) {
- final long initialLimit =
- mCompleteEconomicPolicy.getInitialSatiatedConsumptionLimit();
- final long hardLimit = mCompleteEconomicPolicy.getHardSatiatedConsumptionLimit();
+ final long minLimit = mCompleteEconomicPolicy.getMinSatiatedConsumptionLimit();
+ final long maxLimit = mCompleteEconomicPolicy.getMaxSatiatedConsumptionLimit();
final int oldEnabledPolicies = mCompleteEconomicPolicy.getEnabledPolicyIds();
mCompleteEconomicPolicy.tearDown();
mCompleteEconomicPolicy = new CompleteEconomicPolicy(InternalResourceService.this);
if (mIsEnabled && mBootPhase >= PHASE_THIRD_PARTY_APPS_CAN_START) {
mCompleteEconomicPolicy.setup(getAllDeviceConfigProperties());
- if (initialLimit != mCompleteEconomicPolicy.getInitialSatiatedConsumptionLimit()
- || hardLimit
- != mCompleteEconomicPolicy.getHardSatiatedConsumptionLimit()) {
+ if (minLimit != mCompleteEconomicPolicy.getMinSatiatedConsumptionLimit()
+ || maxLimit
+ != mCompleteEconomicPolicy.getMaxSatiatedConsumptionLimit()) {
// Reset the consumption limit since several factors may have changed.
mScribe.setConsumptionLimitLocked(
mCompleteEconomicPolicy.getInitialSatiatedConsumptionLimit());
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/JobSchedulerEconomicPolicy.java b/apex/jobscheduler/service/java/com/android/server/tare/JobSchedulerEconomicPolicy.java
index 71c6d09..7cf459c 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/JobSchedulerEconomicPolicy.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/JobSchedulerEconomicPolicy.java
@@ -38,9 +38,10 @@
import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_MIN_START_CTP_CAKES;
import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_TIMEOUT_PENALTY_BASE_PRICE_CAKES;
import static android.app.tare.EconomyManager.DEFAULT_JS_ACTION_JOB_TIMEOUT_PENALTY_CTP_CAKES;
-import static android.app.tare.EconomyManager.DEFAULT_JS_HARD_CONSUMPTION_LIMIT_CAKES;
import static android.app.tare.EconomyManager.DEFAULT_JS_INITIAL_CONSUMPTION_LIMIT_CAKES;
+import static android.app.tare.EconomyManager.DEFAULT_JS_MAX_CONSUMPTION_LIMIT_CAKES;
import static android.app.tare.EconomyManager.DEFAULT_JS_MAX_SATIATED_BALANCE_CAKES;
+import static android.app.tare.EconomyManager.DEFAULT_JS_MIN_CONSUMPTION_LIMIT_CAKES;
import static android.app.tare.EconomyManager.DEFAULT_JS_MIN_SATIATED_BALANCE_EXEMPTED_CAKES;
import static android.app.tare.EconomyManager.DEFAULT_JS_MIN_SATIATED_BALANCE_INCREMENT_APP_UPDATER_CAKES;
import static android.app.tare.EconomyManager.DEFAULT_JS_MIN_SATIATED_BALANCE_OTHER_APP_CAKES;
@@ -84,9 +85,10 @@
import static android.app.tare.EconomyManager.KEY_JS_ACTION_JOB_MIN_START_CTP;
import static android.app.tare.EconomyManager.KEY_JS_ACTION_JOB_TIMEOUT_PENALTY_BASE_PRICE;
import static android.app.tare.EconomyManager.KEY_JS_ACTION_JOB_TIMEOUT_PENALTY_CTP;
-import static android.app.tare.EconomyManager.KEY_JS_HARD_CONSUMPTION_LIMIT;
import static android.app.tare.EconomyManager.KEY_JS_INITIAL_CONSUMPTION_LIMIT;
+import static android.app.tare.EconomyManager.KEY_JS_MAX_CONSUMPTION_LIMIT;
import static android.app.tare.EconomyManager.KEY_JS_MAX_SATIATED_BALANCE;
+import static android.app.tare.EconomyManager.KEY_JS_MIN_CONSUMPTION_LIMIT;
import static android.app.tare.EconomyManager.KEY_JS_MIN_SATIATED_BALANCE_EXEMPTED;
import static android.app.tare.EconomyManager.KEY_JS_MIN_SATIATED_BALANCE_INCREMENT_APP_UPDATER;
import static android.app.tare.EconomyManager.KEY_JS_MIN_SATIATED_BALANCE_OTHER_APP;
@@ -159,7 +161,8 @@
private long mMinSatiatedBalanceIncrementalAppUpdater;
private long mMaxSatiatedBalance;
private long mInitialSatiatedConsumptionLimit;
- private long mHardSatiatedConsumptionLimit;
+ private long mMinSatiatedConsumptionLimit;
+ private long mMaxSatiatedConsumptionLimit;
private final KeyValueListParser mParser = new KeyValueListParser(',');
private final Injector mInjector;
@@ -216,8 +219,13 @@
}
@Override
- long getHardSatiatedConsumptionLimit() {
- return mHardSatiatedConsumptionLimit;
+ long getMinSatiatedConsumptionLimit() {
+ return mMinSatiatedConsumptionLimit;
+ }
+
+ @Override
+ long getMaxSatiatedConsumptionLimit() {
+ return mMaxSatiatedConsumptionLimit;
}
@NonNull
@@ -260,12 +268,15 @@
mMaxSatiatedBalance = getConstantAsCake(mParser, properties,
KEY_JS_MAX_SATIATED_BALANCE, DEFAULT_JS_MAX_SATIATED_BALANCE_CAKES,
Math.max(arcToCake(1), mMinSatiatedBalanceExempted));
+ mMinSatiatedConsumptionLimit = getConstantAsCake(mParser, properties,
+ KEY_JS_MIN_CONSUMPTION_LIMIT, DEFAULT_JS_MIN_CONSUMPTION_LIMIT_CAKES,
+ arcToCake(1));
mInitialSatiatedConsumptionLimit = getConstantAsCake(mParser, properties,
- KEY_JS_INITIAL_CONSUMPTION_LIMIT, DEFAULT_JS_INITIAL_CONSUMPTION_LIMIT_CAKES,
- arcToCake(1));
- mHardSatiatedConsumptionLimit = getConstantAsCake(mParser, properties,
- KEY_JS_HARD_CONSUMPTION_LIMIT, DEFAULT_JS_HARD_CONSUMPTION_LIMIT_CAKES,
- mInitialSatiatedConsumptionLimit);
+ KEY_JS_INITIAL_CONSUMPTION_LIMIT, DEFAULT_JS_INITIAL_CONSUMPTION_LIMIT_CAKES,
+ mMinSatiatedConsumptionLimit);
+ mMaxSatiatedConsumptionLimit = getConstantAsCake(mParser, properties,
+ KEY_JS_MAX_CONSUMPTION_LIMIT, DEFAULT_JS_MAX_CONSUMPTION_LIMIT_CAKES,
+ mInitialSatiatedConsumptionLimit);
mActions.put(ACTION_JOB_MAX_START, new Action(ACTION_JOB_MAX_START,
getConstantAsCake(mParser, properties,
@@ -420,9 +431,11 @@
pw.decreaseIndent();
pw.print("Max satiated balance", cakeToString(mMaxSatiatedBalance)).println();
pw.print("Consumption limits: [");
+ pw.print(cakeToString(mMinSatiatedConsumptionLimit));
+ pw.print(", ");
pw.print(cakeToString(mInitialSatiatedConsumptionLimit));
pw.print(", ");
- pw.print(cakeToString(mHardSatiatedConsumptionLimit));
+ pw.print(cakeToString(mMaxSatiatedConsumptionLimit));
pw.println("]");
pw.println();
diff --git a/core/api/current.txt b/core/api/current.txt
index cfaacfe..19b476a 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -143,6 +143,7 @@
field public static final String READ_MEDIA_AUDIO = "android.permission.READ_MEDIA_AUDIO";
field public static final String READ_MEDIA_IMAGES = "android.permission.READ_MEDIA_IMAGES";
field public static final String READ_MEDIA_VIDEO = "android.permission.READ_MEDIA_VIDEO";
+ field public static final String READ_MEDIA_VISUAL_USER_SELECTED = "android.permission.READ_MEDIA_VISUAL_USER_SELECTED";
field public static final String READ_NEARBY_STREAMING_POLICY = "android.permission.READ_NEARBY_STREAMING_POLICY";
field public static final String READ_PHONE_NUMBERS = "android.permission.READ_PHONE_NUMBERS";
field public static final String READ_PHONE_STATE = "android.permission.READ_PHONE_STATE";
@@ -4604,23 +4605,24 @@
public class AlarmManager {
method public boolean canScheduleExactAlarms();
- method public void cancel(android.app.PendingIntent);
- method public void cancel(android.app.AlarmManager.OnAlarmListener);
+ method public void cancel(@NonNull android.app.PendingIntent);
+ method public void cancel(@NonNull android.app.AlarmManager.OnAlarmListener);
method public void cancelAll();
method public android.app.AlarmManager.AlarmClockInfo getNextAlarmClock();
- method public void set(int, long, android.app.PendingIntent);
- method public void set(int, long, String, android.app.AlarmManager.OnAlarmListener, android.os.Handler);
- method @RequiresPermission(android.Manifest.permission.SCHEDULE_EXACT_ALARM) public void setAlarmClock(android.app.AlarmManager.AlarmClockInfo, android.app.PendingIntent);
- method public void setAndAllowWhileIdle(int, long, android.app.PendingIntent);
- method @RequiresPermission(value=android.Manifest.permission.SCHEDULE_EXACT_ALARM, conditional=true) public void setExact(int, long, android.app.PendingIntent);
- method @RequiresPermission(value=android.Manifest.permission.SCHEDULE_EXACT_ALARM, conditional=true) public void setExact(int, long, String, android.app.AlarmManager.OnAlarmListener, android.os.Handler);
- method @RequiresPermission(value=android.Manifest.permission.SCHEDULE_EXACT_ALARM, conditional=true) public void setExactAndAllowWhileIdle(int, long, android.app.PendingIntent);
- method public void setInexactRepeating(int, long, long, android.app.PendingIntent);
- method public void setRepeating(int, long, long, android.app.PendingIntent);
+ method public void set(int, long, @NonNull android.app.PendingIntent);
+ method public void set(int, long, @Nullable String, @NonNull android.app.AlarmManager.OnAlarmListener, @Nullable android.os.Handler);
+ method @RequiresPermission(android.Manifest.permission.SCHEDULE_EXACT_ALARM) public void setAlarmClock(@NonNull android.app.AlarmManager.AlarmClockInfo, @NonNull android.app.PendingIntent);
+ method public void setAndAllowWhileIdle(int, long, @NonNull android.app.PendingIntent);
+ method @RequiresPermission(value=android.Manifest.permission.SCHEDULE_EXACT_ALARM, conditional=true) public void setExact(int, long, @NonNull android.app.PendingIntent);
+ method @RequiresPermission(value=android.Manifest.permission.SCHEDULE_EXACT_ALARM, conditional=true) public void setExact(int, long, @Nullable String, @NonNull android.app.AlarmManager.OnAlarmListener, @Nullable android.os.Handler);
+ method @RequiresPermission(value=android.Manifest.permission.SCHEDULE_EXACT_ALARM, conditional=true) public void setExactAndAllowWhileIdle(int, long, @NonNull android.app.PendingIntent);
+ method public void setInexactRepeating(int, long, long, @NonNull android.app.PendingIntent);
+ method public void setRepeating(int, long, long, @NonNull android.app.PendingIntent);
method @RequiresPermission(android.Manifest.permission.SET_TIME) public void setTime(long);
method @RequiresPermission(android.Manifest.permission.SET_TIME_ZONE) public void setTimeZone(String);
- method public void setWindow(int, long, long, android.app.PendingIntent);
- method public void setWindow(int, long, long, String, android.app.AlarmManager.OnAlarmListener, android.os.Handler);
+ method public void setWindow(int, long, long, @NonNull android.app.PendingIntent);
+ method public void setWindow(int, long, long, @Nullable String, @NonNull android.app.AlarmManager.OnAlarmListener, @Nullable android.os.Handler);
+ method public void setWindow(int, long, long, @Nullable String, @NonNull java.util.concurrent.Executor, @NonNull android.app.AlarmManager.OnAlarmListener);
field public static final String ACTION_NEXT_ALARM_CLOCK_CHANGED = "android.app.action.NEXT_ALARM_CLOCK_CHANGED";
field public static final String ACTION_SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED = "android.app.action.SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED";
field public static final int ELAPSED_REALTIME = 3; // 0x3
@@ -8954,9 +8956,18 @@
package android.companion {
+ public final class AssociatedDevice implements android.os.Parcelable {
+ method public int describeContents();
+ method @Nullable public android.bluetooth.le.ScanResult getBleDevice();
+ method @Nullable public android.bluetooth.BluetoothDevice getBluetoothDevice();
+ method @Nullable public android.net.wifi.ScanResult getWifiDevice();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.companion.AssociatedDevice> CREATOR;
+ }
+
public final class AssociationInfo implements android.os.Parcelable {
method public int describeContents();
- method @Nullable public android.os.Parcelable getAssociatedDevice();
+ method @Nullable public android.companion.AssociatedDevice getAssociatedDevice();
method @Nullable public android.net.MacAddress getDeviceMacAddress();
method @Nullable public String getDeviceProfile();
method @Nullable public CharSequence getDisplayName();
@@ -11654,7 +11665,7 @@
public static final class PackageInstaller.PreapprovalDetails implements android.os.Parcelable {
method public int describeContents();
method @Nullable public android.graphics.Bitmap getIcon();
- method @NonNull public String getLabel();
+ method @NonNull public CharSequence getLabel();
method @NonNull public android.icu.util.ULocale getLocale();
method @NonNull public String getPackageName();
method public void writeToParcel(@NonNull android.os.Parcel, int);
@@ -11665,7 +11676,7 @@
ctor public PackageInstaller.PreapprovalDetails.Builder();
method @NonNull public android.content.pm.PackageInstaller.PreapprovalDetails build();
method @NonNull public android.content.pm.PackageInstaller.PreapprovalDetails.Builder setIcon(@NonNull android.graphics.Bitmap);
- method @NonNull public android.content.pm.PackageInstaller.PreapprovalDetails.Builder setLabel(@NonNull String);
+ method @NonNull public android.content.pm.PackageInstaller.PreapprovalDetails.Builder setLabel(@NonNull CharSequence);
method @NonNull public android.content.pm.PackageInstaller.PreapprovalDetails.Builder setLocale(@NonNull android.icu.util.ULocale);
method @NonNull public android.content.pm.PackageInstaller.PreapprovalDetails.Builder setPackageName(@NonNull String);
}
@@ -32545,6 +32556,7 @@
field public static final String DISALLOW_BLUETOOTH = "no_bluetooth";
field public static final String DISALLOW_BLUETOOTH_SHARING = "no_bluetooth_sharing";
field public static final String DISALLOW_CAMERA_TOGGLE = "disallow_camera_toggle";
+ field public static final String DISALLOW_CELLULAR_2G = "no_cellular_2g";
field public static final String DISALLOW_CHANGE_WIFI_STATE = "no_change_wifi_state";
field public static final String DISALLOW_CONFIG_BLUETOOTH = "no_config_bluetooth";
field public static final String DISALLOW_CONFIG_BRIGHTNESS = "no_config_brightness";
@@ -41591,7 +41603,7 @@
field public static final String KEY_CARRIER_CONFIG_APPLIED_BOOL = "carrier_config_applied_bool";
field public static final String KEY_CARRIER_CONFIG_VERSION_STRING = "carrier_config_version_string";
field public static final String KEY_CARRIER_CROSS_SIM_IMS_AVAILABLE_BOOL = "carrier_cross_sim_ims_available_bool";
- field public static final String KEY_CARRIER_DATA_CALL_PERMANENT_FAILURE_STRINGS = "carrier_data_call_permanent_failure_strings";
+ field @Deprecated public static final String KEY_CARRIER_DATA_CALL_PERMANENT_FAILURE_STRINGS = "carrier_data_call_permanent_failure_strings";
field public static final String KEY_CARRIER_DEFAULT_ACTIONS_ON_DCFAILURE_STRING_ARRAY = "carrier_default_actions_on_dcfailure_string_array";
field public static final String KEY_CARRIER_DEFAULT_ACTIONS_ON_DEFAULT_NETWORK_AVAILABLE = "carrier_default_actions_on_default_network_available_string_array";
field public static final String KEY_CARRIER_DEFAULT_ACTIONS_ON_REDIRECTION_STRING_ARRAY = "carrier_default_actions_on_redirection_string_array";
@@ -41728,6 +41740,7 @@
field public static final String KEY_MMS_MMS_READ_REPORT_ENABLED_BOOL = "enableMMSReadReports";
field public static final String KEY_MMS_MULTIPART_SMS_ENABLED_BOOL = "enableMultipartSMS";
field public static final String KEY_MMS_NAI_SUFFIX_STRING = "naiSuffix";
+ field public static final String KEY_MMS_NETWORK_RELEASE_TIMEOUT_MILLIS_INT = "mms_network_release_timeout_millis_int";
field public static final String KEY_MMS_NOTIFY_WAP_MMSC_ENABLED_BOOL = "enabledNotifyWapMMSC";
field public static final String KEY_MMS_RECIPIENT_LIMIT_INT = "recipientLimit";
field public static final String KEY_MMS_SEND_MULTIPART_SMS_AS_SEPARATE_MESSAGES_BOOL = "sendMultipartSmsAsSeparateMessages";
@@ -41759,6 +41772,7 @@
field public static final String KEY_PING_TEST_BEFORE_DATA_SWITCH_BOOL = "ping_test_before_data_switch_bool";
field public static final String KEY_PREFER_2G_BOOL = "prefer_2g_bool";
field public static final String KEY_PREMIUM_CAPABILITY_MAXIMUM_NOTIFICATION_COUNT_INT_ARRAY = "premium_capability_maximum_notification_count_int_array";
+ field public static final String KEY_PREMIUM_CAPABILITY_NETWORK_SETUP_TIME_MILLIS_LONG = "premium_capability_network_setup_time_millis_long";
field public static final String KEY_PREMIUM_CAPABILITY_NOTIFICATION_BACKOFF_HYSTERESIS_TIME_MILLIS_LONG = "premium_capability_notification_backoff_hysteresis_time_millis_long";
field public static final String KEY_PREMIUM_CAPABILITY_NOTIFICATION_DISPLAY_TIMEOUT_MILLIS_LONG = "premium_capability_notification_display_timeout_millis_long";
field public static final String KEY_PREMIUM_CAPABILITY_PURCHASE_CONDITION_BACKOFF_HYSTERESIS_TIME_MILLIS_LONG = "premium_capability_purchase_condition_backoff_hysteresis_time_millis_long";
@@ -43416,14 +43430,18 @@
field public static final int RESULT_RECEIVE_WHILE_ENCRYPTED = 504; // 0x1f8
field public static final int RESULT_REMOTE_EXCEPTION = 31; // 0x1f
field public static final int RESULT_REQUEST_NOT_SUPPORTED = 24; // 0x18
+ field public static final int RESULT_RIL_ABORTED = 137; // 0x89
field public static final int RESULT_RIL_ACCESS_BARRED = 122; // 0x7a
field public static final int RESULT_RIL_BLOCKED_DUE_TO_CALL = 123; // 0x7b
field public static final int RESULT_RIL_CANCELLED = 119; // 0x77
+ field public static final int RESULT_RIL_DEVICE_IN_USE = 136; // 0x88
field public static final int RESULT_RIL_ENCODING_ERR = 109; // 0x6d
field public static final int RESULT_RIL_GENERIC_ERROR = 124; // 0x7c
field public static final int RESULT_RIL_INTERNAL_ERR = 113; // 0x71
field public static final int RESULT_RIL_INVALID_ARGUMENTS = 104; // 0x68
field public static final int RESULT_RIL_INVALID_MODEM_STATE = 115; // 0x73
+ field public static final int RESULT_RIL_INVALID_RESPONSE = 125; // 0x7d
+ field public static final int RESULT_RIL_INVALID_SIM_STATE = 130; // 0x82
field public static final int RESULT_RIL_INVALID_SMSC_ADDRESS = 110; // 0x6e
field public static final int RESULT_RIL_INVALID_SMS_FORMAT = 107; // 0x6b
field public static final int RESULT_RIL_INVALID_STATE = 103; // 0x67
@@ -43432,14 +43450,23 @@
field public static final int RESULT_RIL_NETWORK_NOT_READY = 116; // 0x74
field public static final int RESULT_RIL_NETWORK_REJECT = 102; // 0x66
field public static final int RESULT_RIL_NO_MEMORY = 105; // 0x69
+ field public static final int RESULT_RIL_NO_NETWORK_FOUND = 135; // 0x87
field public static final int RESULT_RIL_NO_RESOURCES = 118; // 0x76
+ field public static final int RESULT_RIL_NO_SMS_TO_ACK = 131; // 0x83
+ field public static final int RESULT_RIL_NO_SUBSCRIPTION = 134; // 0x86
field public static final int RESULT_RIL_OPERATION_NOT_ALLOWED = 117; // 0x75
field public static final int RESULT_RIL_RADIO_NOT_AVAILABLE = 100; // 0x64
field public static final int RESULT_RIL_REQUEST_NOT_SUPPORTED = 114; // 0x72
field public static final int RESULT_RIL_REQUEST_RATE_LIMITED = 106; // 0x6a
field public static final int RESULT_RIL_SIMULTANEOUS_SMS_AND_CALL_NOT_ALLOWED = 121; // 0x79
field public static final int RESULT_RIL_SIM_ABSENT = 120; // 0x78
+ field public static final int RESULT_RIL_SIM_BUSY = 132; // 0x84
+ field public static final int RESULT_RIL_SIM_ERROR = 129; // 0x81
+ field public static final int RESULT_RIL_SIM_FULL = 133; // 0x85
+ field public static final int RESULT_RIL_SIM_PIN2 = 126; // 0x7e
+ field public static final int RESULT_RIL_SIM_PUK2 = 127; // 0x7f
field public static final int RESULT_RIL_SMS_SEND_FAIL_RETRY = 101; // 0x65
+ field public static final int RESULT_RIL_SUBSCRIPTION_NOT_AVAILABLE = 128; // 0x80
field public static final int RESULT_RIL_SYSTEM_ERR = 108; // 0x6c
field public static final int RESULT_SMS_BLOCKED_DURING_EMERGENCY = 29; // 0x1d
field public static final int RESULT_SMS_SEND_RETRY_FAILED = 30; // 0x1e
@@ -44053,6 +44080,7 @@
field public static final int PURCHASE_PREMIUM_CAPABILITY_RESULT_NETWORK_NOT_AVAILABLE = 12; // 0xc
field public static final int PURCHASE_PREMIUM_CAPABILITY_RESULT_NOT_DEFAULT_DATA = 14; // 0xe
field public static final int PURCHASE_PREMIUM_CAPABILITY_RESULT_OVERRIDDEN = 5; // 0x5
+ field public static final int PURCHASE_PREMIUM_CAPABILITY_RESULT_PENDING_NETWORK_SETUP = 15; // 0xf
field public static final int PURCHASE_PREMIUM_CAPABILITY_RESULT_REQUEST_FAILED = 11; // 0xb
field public static final int PURCHASE_PREMIUM_CAPABILITY_RESULT_SUCCESS = 1; // 0x1
field public static final int PURCHASE_PREMIUM_CAPABILITY_RESULT_THROTTLED = 2; // 0x2
@@ -45568,6 +45596,14 @@
field public static final int DONE = -1; // 0xffffffff
}
+ public static class SegmentFinder.DefaultSegmentFinder extends android.text.SegmentFinder {
+ ctor public SegmentFinder.DefaultSegmentFinder(@NonNull int[]);
+ method public int nextEndBoundary(@IntRange(from=0) int);
+ method public int nextStartBoundary(@IntRange(from=0) int);
+ method public int previousEndBoundary(@IntRange(from=0) int);
+ method public int previousStartBoundary(@IntRange(from=0) int);
+ }
+
public class Selection {
method public static boolean extendDown(android.text.Spannable, android.text.Layout);
method public static boolean extendLeft(android.text.Spannable, android.text.Layout);
@@ -48557,6 +48593,12 @@
field public static final int VERTICAL_GRAVITY_MASK = 112; // 0x70
}
+ public class HandwritingDelegateConfiguration {
+ ctor public HandwritingDelegateConfiguration(@IdRes int, @NonNull Runnable);
+ method public int getDelegatorViewId();
+ method @NonNull public Runnable getInitiationCallback();
+ }
+
public class HapticFeedbackConstants {
field public static final int CLOCK_TICK = 4; // 0x4
field public static final int CONFIRM = 16; // 0x10
@@ -49574,16 +49616,13 @@
}
public final class PixelCopy {
- method @NonNull public static android.view.PixelCopy.Request ofSurface(@NonNull android.view.Surface, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.view.PixelCopy.CopyResult>);
- method @NonNull public static android.view.PixelCopy.Request ofSurface(@NonNull android.view.SurfaceView, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.view.PixelCopy.CopyResult>);
- method @NonNull public static android.view.PixelCopy.Request ofWindow(@NonNull android.view.Window, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.view.PixelCopy.CopyResult>);
- method @NonNull public static android.view.PixelCopy.Request ofWindow(@NonNull android.view.View, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.view.PixelCopy.CopyResult>);
method public static void request(@NonNull android.view.SurfaceView, @NonNull android.graphics.Bitmap, @NonNull android.view.PixelCopy.OnPixelCopyFinishedListener, @NonNull android.os.Handler);
method public static void request(@NonNull android.view.SurfaceView, @Nullable android.graphics.Rect, @NonNull android.graphics.Bitmap, @NonNull android.view.PixelCopy.OnPixelCopyFinishedListener, @NonNull android.os.Handler);
method public static void request(@NonNull android.view.Surface, @NonNull android.graphics.Bitmap, @NonNull android.view.PixelCopy.OnPixelCopyFinishedListener, @NonNull android.os.Handler);
method public static void request(@NonNull android.view.Surface, @Nullable android.graphics.Rect, @NonNull android.graphics.Bitmap, @NonNull android.view.PixelCopy.OnPixelCopyFinishedListener, @NonNull android.os.Handler);
method public static void request(@NonNull android.view.Window, @NonNull android.graphics.Bitmap, @NonNull android.view.PixelCopy.OnPixelCopyFinishedListener, @NonNull android.os.Handler);
method public static void request(@NonNull android.view.Window, @Nullable android.graphics.Rect, @NonNull android.graphics.Bitmap, @NonNull android.view.PixelCopy.OnPixelCopyFinishedListener, @NonNull android.os.Handler);
+ method public static void request(@NonNull android.view.PixelCopy.Request);
field public static final int ERROR_DESTINATION_INVALID = 5; // 0x5
field public static final int ERROR_SOURCE_INVALID = 4; // 0x4
field public static final int ERROR_SOURCE_NO_DATA = 3; // 0x3
@@ -49592,19 +49631,28 @@
field public static final int SUCCESS = 0; // 0x0
}
- public static final class PixelCopy.CopyResult {
- method @NonNull public android.graphics.Bitmap getBitmap();
- method public int getStatus();
- }
-
public static interface PixelCopy.OnPixelCopyFinishedListener {
method public void onPixelCopyFinished(int);
}
public static final class PixelCopy.Request {
- method public void request();
- method @NonNull public android.view.PixelCopy.Request setDestinationBitmap(@Nullable android.graphics.Bitmap);
- method @NonNull public android.view.PixelCopy.Request setSourceRect(@Nullable android.graphics.Rect);
+ method @Nullable public android.graphics.Bitmap getDestinationBitmap();
+ method @Nullable public android.graphics.Rect getSourceRect();
+ method @NonNull public static android.view.PixelCopy.Request.Builder ofSurface(@NonNull android.view.Surface, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.view.PixelCopy.Result>);
+ method @NonNull public static android.view.PixelCopy.Request.Builder ofSurface(@NonNull android.view.SurfaceView, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.view.PixelCopy.Result>);
+ method @NonNull public static android.view.PixelCopy.Request.Builder ofWindow(@NonNull android.view.Window, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.view.PixelCopy.Result>);
+ method @NonNull public static android.view.PixelCopy.Request.Builder ofWindow(@NonNull android.view.View, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.view.PixelCopy.Result>);
+ }
+
+ public static final class PixelCopy.Request.Builder {
+ method @NonNull public android.view.PixelCopy.Request build();
+ method @NonNull public android.view.PixelCopy.Request.Builder setDestinationBitmap(@Nullable android.graphics.Bitmap);
+ method @NonNull public android.view.PixelCopy.Request.Builder setSourceRect(@Nullable android.graphics.Rect);
+ }
+
+ public static final class PixelCopy.Result {
+ method @NonNull public android.graphics.Bitmap getBitmap();
+ method public int getStatus();
}
public final class PointerIcon implements android.os.Parcelable {
@@ -50167,6 +50215,7 @@
method public float getHandwritingBoundsOffsetLeft();
method public float getHandwritingBoundsOffsetRight();
method public float getHandwritingBoundsOffsetTop();
+ method @Nullable public android.view.HandwritingDelegateConfiguration getHandwritingDelegateConfiguration();
method public final boolean getHasOverlappingRendering();
method public final int getHeight();
method public void getHitRect(android.graphics.Rect);
@@ -50533,6 +50582,7 @@
method public void setForegroundTintList(@Nullable android.content.res.ColorStateList);
method public void setForegroundTintMode(@Nullable android.graphics.PorterDuff.Mode);
method public void setHandwritingBoundsOffsets(float, float, float, float);
+ method public void setHandwritingDelegateConfiguration(@Nullable android.view.HandwritingDelegateConfiguration);
method public void setHapticFeedbackEnabled(boolean);
method public void setHasTransientState(boolean);
method public void setHorizontalFadingEdgeEnabled(boolean);
@@ -53575,6 +53625,7 @@
method public boolean reportFullscreenMode(boolean);
method public boolean requestCursorUpdates(int);
method public default boolean requestCursorUpdates(int, int);
+ method public default void requestTextBoundsInfo(@NonNull android.graphics.RectF, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.view.inputmethod.TextBoundsInfoResult>);
method public boolean sendKeyEvent(android.view.KeyEvent);
method public boolean setComposingRegion(int, int);
method public default boolean setComposingRegion(int, int, @Nullable android.view.inputmethod.TextAttribute);
@@ -53904,6 +53955,50 @@
method @NonNull public android.view.inputmethod.TextAttribute.Builder setTextConversionSuggestions(@NonNull java.util.List<java.lang.String>);
}
+ public final class TextBoundsInfo implements android.os.Parcelable {
+ method public int describeContents();
+ method @IntRange(from=0, to=125) public int getCharacterBidiLevel(int);
+ method @NonNull public android.graphics.RectF getCharacterBounds(int);
+ method public int getCharacterFlags(int);
+ method public int getEnd();
+ method @NonNull public android.text.SegmentFinder getGraphemeSegmentFinder();
+ method @NonNull public android.text.SegmentFinder getLineSegmentFinder();
+ method @NonNull public android.graphics.Matrix getMatrix();
+ method public int getStart();
+ method @NonNull public android.text.SegmentFinder getWordSegmentFinder();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.view.inputmethod.TextBoundsInfo> CREATOR;
+ field public static final int FLAG_CHARACTER_LINEFEED = 2; // 0x2
+ field public static final int FLAG_CHARACTER_PUNCTUATION = 4; // 0x4
+ field public static final int FLAG_CHARACTER_WHITESPACE = 1; // 0x1
+ field public static final int FLAG_LINE_IS_RTL = 8; // 0x8
+ }
+
+ public static final class TextBoundsInfo.Builder {
+ ctor public TextBoundsInfo.Builder();
+ method @NonNull public android.view.inputmethod.TextBoundsInfo build();
+ method @NonNull public android.view.inputmethod.TextBoundsInfo.Builder clear();
+ method @NonNull public android.view.inputmethod.TextBoundsInfo.Builder setCharacterBidiLevel(@NonNull int[]);
+ method @NonNull public android.view.inputmethod.TextBoundsInfo.Builder setCharacterBounds(@NonNull float[]);
+ method @NonNull public android.view.inputmethod.TextBoundsInfo.Builder setCharacterFlags(@NonNull int[]);
+ method @NonNull public android.view.inputmethod.TextBoundsInfo.Builder setGraphemeSegmentFinder(@NonNull android.text.SegmentFinder);
+ method @NonNull public android.view.inputmethod.TextBoundsInfo.Builder setLineSegmentFinder(@NonNull android.text.SegmentFinder);
+ method @NonNull public android.view.inputmethod.TextBoundsInfo.Builder setMatrix(@NonNull android.graphics.Matrix);
+ method @NonNull public android.view.inputmethod.TextBoundsInfo.Builder setStartAndEnd(@IntRange(from=0) int, @IntRange(from=0) int);
+ method @NonNull public android.view.inputmethod.TextBoundsInfo.Builder setWordSegmentFinder(@NonNull android.text.SegmentFinder);
+ }
+
+ public final class TextBoundsInfoResult {
+ ctor public TextBoundsInfoResult(int);
+ ctor public TextBoundsInfoResult(int, @NonNull android.view.inputmethod.TextBoundsInfo);
+ method public int getResultCode();
+ method @Nullable public android.view.inputmethod.TextBoundsInfo getTextBoundsInfo();
+ field public static final int CODE_CANCELLED = 3; // 0x3
+ field public static final int CODE_FAILED = 2; // 0x2
+ field public static final int CODE_SUCCESS = 1; // 0x1
+ field public static final int CODE_UNSUPPORTED = 0; // 0x0
+ }
+
public final class TextSnapshot {
ctor public TextSnapshot(@NonNull android.view.inputmethod.SurroundingText, @IntRange(from=0xffffffff) int, @IntRange(from=0xffffffff) int, int);
method @IntRange(from=0xffffffff) public int getCompositionEnd();
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index 88efcce..ce18745 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -340,10 +340,6 @@
method public boolean shouldBypassCache(@NonNull Q);
}
- public interface Parcelable {
- method public default int getStability();
- }
-
public class Process {
method public static final int getAppUidForSdkSandboxUid(int);
method public static final boolean isSdkSandboxUid(int);
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index a382ecf..352b4f9 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -524,10 +524,12 @@
}
public class AlarmManager {
- method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void set(int, long, long, long, android.app.PendingIntent, android.os.WorkSource);
- method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void set(int, long, long, long, android.app.AlarmManager.OnAlarmListener, android.os.Handler, android.os.WorkSource);
+ method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void set(int, long, long, long, @NonNull android.app.PendingIntent, @Nullable android.os.WorkSource);
+ method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void set(int, long, long, long, @NonNull android.app.AlarmManager.OnAlarmListener, @Nullable android.os.Handler, @Nullable android.os.WorkSource);
method @RequiresPermission(allOf={android.Manifest.permission.UPDATE_DEVICE_STATS, android.Manifest.permission.SCHEDULE_EXACT_ALARM}, conditional=true) public void setExact(int, long, @Nullable String, @NonNull java.util.concurrent.Executor, @NonNull android.os.WorkSource, @NonNull android.app.AlarmManager.OnAlarmListener);
+ method @RequiresPermission(allOf={android.Manifest.permission.UPDATE_DEVICE_STATS, android.Manifest.permission.SCHEDULE_EXACT_ALARM}, conditional=true) public void setExactAndAllowWhileIdle(int, long, @Nullable String, @NonNull java.util.concurrent.Executor, @Nullable android.os.WorkSource, @NonNull android.app.AlarmManager.OnAlarmListener);
method @RequiresPermission(android.Manifest.permission.SCHEDULE_PRIORITIZED_ALARM) public void setPrioritized(int, long, long, @Nullable String, @NonNull java.util.concurrent.Executor, @NonNull android.app.AlarmManager.OnAlarmListener);
+ method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void setWindow(int, long, long, @Nullable String, @NonNull java.util.concurrent.Executor, @Nullable android.os.WorkSource, @NonNull android.app.AlarmManager.OnAlarmListener);
}
public class AppOpsManager {
@@ -585,6 +587,7 @@
field public static final String OPSTR_READ_MEDIA_AUDIO = "android:read_media_audio";
field public static final String OPSTR_READ_MEDIA_IMAGES = "android:read_media_images";
field public static final String OPSTR_READ_MEDIA_VIDEO = "android:read_media_video";
+ field public static final String OPSTR_READ_MEDIA_VISUAL_USER_SELECTED = "android:read_media_visual_user_selected";
field public static final String OPSTR_RECEIVE_AMBIENT_TRIGGER_AUDIO = "android:receive_ambient_trigger_audio";
field public static final String OPSTR_RECEIVE_EMERGENCY_BROADCAST = "android:receive_emergency_broadcast";
field public static final String OPSTR_RECEIVE_EXPLICIT_USER_INTERACTION_AUDIO = "android:receive_explicit_user_interaction_audio";
@@ -9670,6 +9673,7 @@
}
public interface Parcelable {
+ method public default int getStability();
field public static final int PARCELABLE_STABILITY_LOCAL = 0; // 0x0
field public static final int PARCELABLE_STABILITY_VINTF = 1; // 0x1
}
@@ -9678,7 +9682,6 @@
ctor public ParcelableHolder(int);
method public int describeContents();
method @Nullable public <T extends android.os.Parcelable> T getParcelable(@NonNull Class<T>);
- method public int getStability();
method public void readFromParcel(@NonNull android.os.Parcel);
method public void setParcelable(@Nullable android.os.Parcelable);
method public void writeToParcel(@NonNull android.os.Parcel, int);
@@ -13704,6 +13707,7 @@
field public static final String ACTION_SIM_SLOT_STATUS_CHANGED = "android.telephony.action.SIM_SLOT_STATUS_CHANGED";
field public static final int ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G = 3; // 0x3
field public static final int ALLOWED_NETWORK_TYPES_REASON_POWER = 1; // 0x1
+ field public static final int ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS = 4; // 0x4
field public static final int CALL_WAITING_STATUS_DISABLED = 2; // 0x2
field public static final int CALL_WAITING_STATUS_ENABLED = 1; // 0x1
field public static final int CALL_WAITING_STATUS_FDN_CHECK_FAILURE = 5; // 0x5
@@ -15921,10 +15925,17 @@
package android.view.accessibility {
+ public abstract class AccessibilityDisplayProxy {
+ ctor public AccessibilityDisplayProxy(int, @NonNull java.util.concurrent.Executor, @NonNull java.util.List<android.accessibilityservice.AccessibilityServiceInfo>);
+ method public int getDisplayId();
+ }
+
public final class AccessibilityManager {
method public int getAccessibilityWindowId(@Nullable android.os.IBinder);
method @RequiresPermission(android.Manifest.permission.MANAGE_ACCESSIBILITY) public void performAccessibilityShortcut();
+ method @RequiresPermission(android.Manifest.permission.MANAGE_ACCESSIBILITY) public boolean registerDisplayProxy(@NonNull android.view.accessibility.AccessibilityDisplayProxy);
method @RequiresPermission(android.Manifest.permission.MANAGE_ACCESSIBILITY) public void registerSystemAction(@NonNull android.app.RemoteAction, int);
+ method @RequiresPermission(android.Manifest.permission.MANAGE_ACCESSIBILITY) public boolean unregisterDisplayProxy(@NonNull android.view.accessibility.AccessibilityDisplayProxy);
method @RequiresPermission(android.Manifest.permission.MANAGE_ACCESSIBILITY) public void unregisterSystemAction(int);
}
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index ef74a3e..e9f9136 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -47,6 +47,7 @@
field public static final String SET_KEYBOARD_LAYOUT = "android.permission.SET_KEYBOARD_LAYOUT";
field public static final String SUSPEND_APPS = "android.permission.SUSPEND_APPS";
field public static final String TEST_BIOMETRIC = "android.permission.TEST_BIOMETRIC";
+ field public static final String TEST_INPUT_METHOD = "android.permission.TEST_INPUT_METHOD";
field public static final String TEST_MANAGE_ROLLBACKS = "android.permission.TEST_MANAGE_ROLLBACKS";
field public static final String UPGRADE_RUNTIME_PERMISSIONS = "android.permission.UPGRADE_RUNTIME_PERMISSIONS";
field public static final String WRITE_DEVICE_CONFIG = "android.permission.WRITE_DEVICE_CONFIG";
@@ -419,7 +420,7 @@
}
public final class SyncNotedAppOp implements android.os.Parcelable {
- ctor public SyncNotedAppOp(int, @IntRange(from=0L) int, @Nullable String, @NonNull String);
+ ctor public SyncNotedAppOp(int, @IntRange(from=0L) int, @Nullable String, @Nullable String);
}
public class TaskInfo {
@@ -3156,12 +3157,12 @@
}
public final class InputMethodManager {
- method public void addVirtualStylusIdForTestSession();
+ method @RequiresPermission(android.Manifest.permission.TEST_INPUT_METHOD) public void addVirtualStylusIdForTestSession();
method public int getDisplayId();
- method @NonNull @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) public java.util.List<android.view.inputmethod.InputMethodInfo> getInputMethodListAsUser(int);
+ method @NonNull @RequiresPermission(value=android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, conditional=true) public java.util.List<android.view.inputmethod.InputMethodInfo> getInputMethodListAsUser(int);
method public boolean hasActiveInputConnection(@Nullable android.view.View);
- method public boolean isInputMethodPickerShown();
- method @RequiresPermission("android.permission.TEST_INPUT_METHOD") public void setStylusWindowIdleTimeoutForTest(long);
+ method @RequiresPermission(android.Manifest.permission.TEST_INPUT_METHOD) public boolean isInputMethodPickerShown();
+ method @RequiresPermission(android.Manifest.permission.TEST_INPUT_METHOD) public void setStylusWindowIdleTimeoutForTest(long);
field public static final long CLEAR_SHOW_FORCED_FLAG_WHEN_LEAVING = 214016041L; // 0xcc1a029L
}
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index 308e996..baa3bd9 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -227,6 +227,12 @@
public abstract boolean isModernQueueEnabled();
/**
+ * Enforce capability restrictions on use of the given BroadcastOptions
+ */
+ public abstract void enforceBroadcastOptionsPermissions(@Nullable Bundle options,
+ int callingUid);
+
+ /**
* Returns package name given pid.
*
* @param pid The pid we are searching package name for.
@@ -300,7 +306,7 @@
public abstract int handleIncomingUser(int callingPid, int callingUid, @UserIdInt int userId,
boolean allowAll, int allowMode, String name, String callerPackage);
- /** Checks if the calling binder pid as the permission. */
+ /** Checks if the calling binder pid/uid has the given permission. */
@PermissionMethod
public abstract void enforceCallingPermission(@PermissionName String permission, String func);
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 1b972e0..267e5b6 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -1360,9 +1360,17 @@
*/
public static final int OP_RUN_LONG_JOBS = AppProtoEnums.APP_OP_RUN_LONG_JOBS;
+ /**
+ * Notify apps that they have been granted URI permission photos
+ *
+ * @hide
+ */
+ public static final int OP_READ_MEDIA_VISUAL_USER_SELECTED =
+ AppProtoEnums.APP_OP_READ_MEDIA_VISUAL_USER_SELECTED;
+
/** @hide */
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- public static final int _NUM_OP = 123;
+ public static final int _NUM_OP = 124;
/** Access to coarse location information. */
public static final String OPSTR_COARSE_LOCATION = "android:coarse_location";
@@ -1833,6 +1841,14 @@
@SystemApi
public static final String OPSTR_RECEIVE_AMBIENT_TRIGGER_AUDIO =
"android:receive_ambient_trigger_audio";
+ /**
+ * Notify apps that they have been granted URI permission photos
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final String OPSTR_READ_MEDIA_VISUAL_USER_SELECTED =
+ "android:read_media_visual_user_selected";
/**
* Record audio from near-field microphone (ie. TV remote)
@@ -1948,6 +1964,7 @@
OP_MANAGE_MEDIA,
OP_TURN_SCREEN_ON,
OP_RUN_LONG_JOBS,
+ OP_READ_MEDIA_VISUAL_USER_SELECTED,
};
static final AppOpInfo[] sAppOpInfos = new AppOpInfo[]{
@@ -2329,7 +2346,11 @@
"RECEIVE_EXPLICIT_USER_INTERACTION_AUDIO").setDefaultMode(
AppOpsManager.MODE_ALLOWED).build(),
new AppOpInfo.Builder(OP_RUN_LONG_JOBS, OPSTR_RUN_LONG_JOBS, "RUN_LONG_JOBS")
- .setPermission(Manifest.permission.RUN_LONG_JOBS).build()
+ .setPermission(Manifest.permission.RUN_LONG_JOBS).build(),
+ new AppOpInfo.Builder(OP_READ_MEDIA_VISUAL_USER_SELECTED,
+ OPSTR_READ_MEDIA_VISUAL_USER_SELECTED, "READ_MEDIA_VISUAL_USER_SELECTED")
+ .setPermission(Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED)
+ .setDefaultMode(AppOpsManager.MODE_ALLOWED).build()
};
/**
diff --git a/core/java/android/app/BroadcastOptions.java b/core/java/android/app/BroadcastOptions.java
index 48638d1..45d4458 100644
--- a/core/java/android/app/BroadcastOptions.java
+++ b/core/java/android/app/BroadcastOptions.java
@@ -636,6 +636,7 @@
* @param broadcastIsInteractive
* @see #isInteractiveBroadcast()
*/
+ @RequiresPermission(android.Manifest.permission.BROADCAST_OPTION_INTERACTIVE)
public void setInteractiveBroadcast(boolean broadcastIsInteractive) {
mIsInteractiveBroadcast = broadcastIsInteractive;
}
diff --git a/core/java/android/app/SyncNotedAppOp.java b/core/java/android/app/SyncNotedAppOp.java
index f156b30..f674e88 100644
--- a/core/java/android/app/SyncNotedAppOp.java
+++ b/core/java/android/app/SyncNotedAppOp.java
@@ -56,7 +56,7 @@
* The package this op applies to
* @hide
*/
- private final @NonNull String mPackageName;
+ private final @Nullable String mPackageName;
/**
* Native code relies on parcel ordering, do not change
@@ -64,7 +64,7 @@
*/
@TestApi
public SyncNotedAppOp(int opMode, @IntRange(from = 0L) int opCode,
- @Nullable String attributionTag, @NonNull String packageName) {
+ @Nullable String attributionTag, @Nullable String packageName) {
this.mOpCode = opCode;
com.android.internal.util.AnnotationValidations.validate(
IntRange.class, null, mOpCode,
@@ -101,7 +101,7 @@
* @hide
*/
public SyncNotedAppOp(@IntRange(from = 0L) int opCode, @Nullable String attributionTag,
- @NonNull String packageName) {
+ @Nullable String packageName) {
this(AppOpsManager.MODE_IGNORED, opCode, attributionTag, packageName);
}
@@ -152,7 +152,7 @@
* @hide
*/
@DataClass.Generated.Member
- public @NonNull String getPackageName() {
+ public @Nullable String getPackageName() {
return mPackageName;
}
@@ -211,11 +211,12 @@
byte flg = 0;
if (mAttributionTag != null) flg |= 0x4;
+ if (mPackageName != null) flg |= 0x8;
dest.writeByte(flg);
dest.writeInt(mOpMode);
dest.writeInt(mOpCode);
if (mAttributionTag != null) dest.writeString(mAttributionTag);
- dest.writeString(mPackageName);
+ if (mPackageName != null) dest.writeString(mPackageName);
}
@Override
@@ -233,7 +234,7 @@
int opMode = in.readInt();
int opCode = in.readInt();
String attributionTag = (flg & 0x4) == 0 ? null : in.readString();
- String packageName = in.readString();
+ String packageName = (flg & 0x8) == 0 ? null : in.readString();
this.mOpMode = opMode;
this.mOpCode = opCode;
@@ -243,8 +244,6 @@
"to", AppOpsManager._NUM_OP - 1);
this.mAttributionTag = attributionTag;
this.mPackageName = packageName;
- com.android.internal.util.AnnotationValidations.validate(
- NonNull.class, null, mPackageName);
// onConstructed(); // You can define this method to get a callback
}
@@ -264,10 +263,10 @@
};
@DataClass.Generated(
- time = 1643320427700L,
+ time = 1667247337573L,
codegenVersion = "1.0.23",
sourceFile = "frameworks/base/core/java/android/app/SyncNotedAppOp.java",
- inputSignatures = "private final int mOpMode\nprivate final @android.annotation.IntRange int mOpCode\nprivate final @android.annotation.Nullable java.lang.String mAttributionTag\nprivate final @android.annotation.NonNull java.lang.String mPackageName\npublic @android.annotation.NonNull java.lang.String getOp()\npublic int getOpMode()\nprivate java.lang.String opCodeToString()\nclass SyncNotedAppOp extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genAidl=true, genConstructor=false, genToString=true)")
+ inputSignatures = "private final int mOpMode\nprivate final @android.annotation.IntRange int mOpCode\nprivate final @android.annotation.Nullable java.lang.String mAttributionTag\nprivate final @android.annotation.Nullable java.lang.String mPackageName\npublic @android.annotation.NonNull java.lang.String getOp()\npublic int getOpMode()\nprivate java.lang.String opCodeToString()\nclass SyncNotedAppOp extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genAidl=true, genConstructor=false, genToString=true)")
@Deprecated
private void __metadata() {}
diff --git a/core/java/android/app/TaskInfo.java b/core/java/android/app/TaskInfo.java
index a2dc47d..5a2f261 100644
--- a/core/java/android/app/TaskInfo.java
+++ b/core/java/android/app/TaskInfo.java
@@ -458,7 +458,8 @@
&& isVisible == that.isVisible
&& isSleeping == that.isSleeping
&& Objects.equals(mTopActivityLocusId, that.mTopActivityLocusId)
- && parentTaskId == that.parentTaskId;
+ && parentTaskId == that.parentTaskId
+ && Objects.equals(topActivity, that.topActivity);
}
/**
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index 95e9c22..5e15b0a 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -2456,7 +2456,12 @@
public void waitForCompletion() {
try {
- mLatch.await(30, TimeUnit.SECONDS);
+ final boolean completed = mLatch.await(30, TimeUnit.SECONDS);
+ if (completed) {
+ Log.d(TAG, "Wallpaper set completion.");
+ } else {
+ Log.d(TAG, "Timeout waiting for wallpaper set completion!");
+ }
} catch (InterruptedException e) {
// This might be legit: the crop may take a very long time. Don't sweat
// it in that case; we are okay with display lagging behind in order to
diff --git a/core/java/android/companion/AssociatedDevice.java b/core/java/android/companion/AssociatedDevice.java
index 3758cdb..a833661 100644
--- a/core/java/android/companion/AssociatedDevice.java
+++ b/core/java/android/companion/AssociatedDevice.java
@@ -16,6 +16,7 @@
package android.companion;
+import android.bluetooth.BluetoothDevice;
import android.os.Parcel;
import android.os.Parcelable;
@@ -23,19 +24,14 @@
import androidx.annotation.Nullable;
/**
- * Loose wrapper around device parcelable. Device can be one of three types:
+ * Container for device info from an association that is not self-managed.
+ * Device can be one of three types:
*
* <ul>
* <li>for classic Bluetooth - {@link android.bluetooth.BluetoothDevice}</li>
* <li>for Bluetooth LE - {@link android.bluetooth.le.ScanResult}</li>
* <li>for WiFi - {@link android.net.wifi.ScanResult}</li>
* </ul>
- *
- * This class serves as temporary wrapper to deliver a loosely-typed parcelable object from
- * {@link com.android.companiondevicemanager.CompanionDeviceActivity} to the Companion app,
- * and should only be used internally.
- *
- * @hide
*/
public final class AssociatedDevice implements Parcelable {
private static final int CLASSIC_BLUETOOTH = 0;
@@ -44,6 +40,7 @@
@NonNull private final Parcelable mDevice;
+ /** @hide */
public AssociatedDevice(@NonNull Parcelable device) {
mDevice = device;
}
@@ -54,11 +51,39 @@
}
/**
- * Return device info. Cast to expected device type.
+ * Return bluetooth device info. Null if associated device is not a bluetooth device.
+ * @return Remote bluetooth device details containing MAC address.
*/
- @NonNull
- public Parcelable getDevice() {
- return mDevice;
+ @Nullable
+ public BluetoothDevice getBluetoothDevice() {
+ if (mDevice instanceof BluetoothDevice) {
+ return (BluetoothDevice) mDevice;
+ }
+ return null;
+ }
+
+ /**
+ * Return bluetooth LE device info. Null if associated device is not a BLE device.
+ * @return BLE scan result containing details of detected BLE device.
+ */
+ @Nullable
+ public android.bluetooth.le.ScanResult getBleDevice() {
+ if (mDevice instanceof android.bluetooth.le.ScanResult) {
+ return (android.bluetooth.le.ScanResult) mDevice;
+ }
+ return null;
+ }
+
+ /**
+ * Return Wi-Fi device info. Null if associated device is not a Wi-Fi device.
+ * @return Wi-Fi scan result containing details of detected access point.
+ */
+ @Nullable
+ public android.net.wifi.ScanResult getWifiDevice() {
+ if (mDevice instanceof android.net.wifi.ScanResult) {
+ return (android.net.wifi.ScanResult) mDevice;
+ }
+ return null;
}
@Override
diff --git a/core/java/android/companion/AssociationInfo.java b/core/java/android/companion/AssociationInfo.java
index 93964b3..5fd39fe 100644
--- a/core/java/android/companion/AssociationInfo.java
+++ b/core/java/android/companion/AssociationInfo.java
@@ -164,20 +164,19 @@
/**
* Companion device that was associated. Note that this field is not persisted across sessions.
- *
- * Cast to expected device type before use:
+ * Device can be one of the following types:
*
* <ul>
- * <li>for classic Bluetooth - {@link android.bluetooth.BluetoothDevice}</li>
- * <li>for Bluetooth LE - {@link android.bluetooth.le.ScanResult}</li>
- * <li>for WiFi - {@link android.net.wifi.ScanResult}</li>
+ * <li>for classic Bluetooth - {@link AssociatedDevice#getBluetoothDevice()}</li>
+ * <li>for Bluetooth LE - {@link AssociatedDevice#getBleDevice()}</li>
+ * <li>for WiFi - {@link AssociatedDevice#getWifiDevice()}</li>
* </ul>
*
* @return the companion device that was associated, or {@code null} if the device is
- * self-managed.
+ * self-managed or this association info was retrieved from persistent storage.
*/
- public @Nullable Parcelable getAssociatedDevice() {
- return mAssociatedDevice == null ? null : mAssociatedDevice.getDevice();
+ public @Nullable AssociatedDevice getAssociatedDevice() {
+ return mAssociatedDevice;
}
/**
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index d2fb1fb..d7686e2 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -3346,7 +3346,7 @@
/**
* The label representing the app to be installed.
*/
- private final @NonNull String mLabel;
+ private final @NonNull CharSequence mLabel;
/**
* The locale of the app label being used.
*/
@@ -3388,7 +3388,7 @@
@DataClass.Generated.Member
public PreapprovalDetails(
@Nullable Bitmap icon,
- @NonNull String label,
+ @NonNull CharSequence label,
@NonNull ULocale locale,
@NonNull String packageName) {
this.mIcon = icon;
@@ -3417,7 +3417,7 @@
* The label representing the app to be installed.
*/
@DataClass.Generated.Member
- public @NonNull String getLabel() {
+ public @NonNull CharSequence getLabel() {
return mLabel;
}
@@ -3461,7 +3461,7 @@
if (mIcon != null) flg |= 0x1;
dest.writeByte(flg);
if (mIcon != null) mIcon.writeToParcel(dest, flags);
- dest.writeString8(mLabel);
+ dest.writeCharSequence(mLabel);
dest.writeString8(mLocale.toString());
dest.writeString8(mPackageName);
}
@@ -3479,7 +3479,7 @@
byte flg = in.readByte();
Bitmap icon = (flg & 0x1) == 0 ? null : Bitmap.CREATOR.createFromParcel(in);
- String label = in.readString8();
+ CharSequence label = (CharSequence) in.readCharSequence();
ULocale locale = new ULocale(in.readString8());
String packageName = in.readString8();
@@ -3519,7 +3519,7 @@
public static final class Builder {
private @Nullable Bitmap mIcon;
- private @NonNull String mLabel;
+ private @NonNull CharSequence mLabel;
private @NonNull ULocale mLocale;
private @NonNull String mPackageName;
@@ -3545,7 +3545,7 @@
* The label representing the app to be installed.
*/
@DataClass.Generated.Member
- public @NonNull Builder setLabel(@NonNull String value) {
+ public @NonNull Builder setLabel(@NonNull CharSequence value) {
checkNotUsed();
mBuilderFieldsSet |= 0x2;
mLabel = value;
@@ -3596,10 +3596,10 @@
}
@DataClass.Generated(
- time = 1664257135109L,
+ time = 1666748098353L,
codegenVersion = "1.0.23",
sourceFile = "frameworks/base/core/java/android/content/pm/PackageInstaller.java",
- inputSignatures = "private final @android.annotation.Nullable android.graphics.Bitmap mIcon\nprivate final @android.annotation.NonNull java.lang.String mLabel\nprivate final @android.annotation.NonNull android.icu.util.ULocale mLocale\nprivate final @android.annotation.NonNull java.lang.String mPackageName\nclass PreapprovalDetails extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genParcelable=true, genHiddenConstructor=true, genBuilder=true, genToString=true)")
+ inputSignatures = "private final @android.annotation.Nullable android.graphics.Bitmap mIcon\nprivate final @android.annotation.NonNull java.lang.CharSequence mLabel\nprivate final @android.annotation.NonNull android.icu.util.ULocale mLocale\nprivate final @android.annotation.NonNull java.lang.String mPackageName\nclass PreapprovalDetails extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genParcelable=true, genHiddenConstructor=true, genBuilder=true, genToString=true)")
@Deprecated
private void __metadata() {}
diff --git a/core/java/android/credentials/Credential.java b/core/java/android/credentials/Credential.java
index fed2592..db89170 100644
--- a/core/java/android/credentials/Credential.java
+++ b/core/java/android/credentials/Credential.java
@@ -36,7 +36,8 @@
*
* @hide
*/
- @NonNull public static final String TYPE_PASSWORD = "android.credentials.TYPE_PASSWORD";
+ @NonNull public static final String TYPE_PASSWORD_CREDENTIAL =
+ "android.credentials.TYPE_PASSWORD_CREDENTIAL";
/**
* The credential type.
diff --git a/core/java/android/credentials/ui/CreateCredentialProviderData.java b/core/java/android/credentials/ui/CreateCredentialProviderData.java
new file mode 100644
index 0000000..9cc9c72
--- /dev/null
+++ b/core/java/android/credentials/ui/CreateCredentialProviderData.java
@@ -0,0 +1,164 @@
+/*
+ * 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 android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.util.AnnotationValidations;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Per-provider metadata and entries for the create-credential flow.
+ *
+ * @hide
+ */
+public class CreateCredentialProviderData extends ProviderData implements Parcelable {
+ @NonNull
+ private final List<Entry> mSaveEntries;
+ @NonNull
+ private final List<Entry> mActionChips;
+ private final boolean mIsDefaultProvider;
+ @Nullable
+ private final Entry mRemoteEntry;
+
+ public CreateCredentialProviderData(
+ @NonNull String providerFlattenedComponentName, @NonNull List<Entry> saveEntries,
+ @NonNull List<Entry> actionChips, boolean isDefaultProvider,
+ @Nullable Entry remoteEntry) {
+ super(providerFlattenedComponentName);
+ mSaveEntries = saveEntries;
+ mActionChips = actionChips;
+ mIsDefaultProvider = isDefaultProvider;
+ mRemoteEntry = remoteEntry;
+ }
+
+ @NonNull
+ public List<Entry> getSaveEntries() {
+ return mSaveEntries;
+ }
+
+ @NonNull
+ public List<Entry> getActionChips() {
+ return mActionChips;
+ }
+
+ public boolean isDefaultProvider() {
+ return mIsDefaultProvider;
+ }
+
+ @Nullable
+ public Entry getRemoteEntry() {
+ return mRemoteEntry;
+ }
+
+ protected CreateCredentialProviderData(@NonNull Parcel in) {
+ super(in);
+
+ List<Entry> credentialEntries = new ArrayList<>();
+ in.readTypedList(credentialEntries, Entry.CREATOR);
+ mSaveEntries = credentialEntries;
+ AnnotationValidations.validate(NonNull.class, null, mSaveEntries);
+
+ List<Entry> actionChips = new ArrayList<>();
+ in.readTypedList(actionChips, Entry.CREATOR);
+ mActionChips = actionChips;
+ AnnotationValidations.validate(NonNull.class, null, mActionChips);
+
+ mIsDefaultProvider = in.readBoolean();
+
+ Entry remoteEntry = in.readTypedObject(Entry.CREATOR);
+ mRemoteEntry = remoteEntry;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ super.writeToParcel(dest, flags);
+ dest.writeTypedList(mSaveEntries);
+ dest.writeTypedList(mActionChips);
+ dest.writeBoolean(isDefaultProvider());
+ dest.writeTypedObject(mRemoteEntry, flags);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ public static final @NonNull Creator<CreateCredentialProviderData> CREATOR =
+ new Creator<CreateCredentialProviderData>() {
+ @Override
+ public CreateCredentialProviderData createFromParcel(@NonNull Parcel in) {
+ return new CreateCredentialProviderData(in);
+ }
+
+ @Override
+ public CreateCredentialProviderData[] newArray(int size) {
+ return new CreateCredentialProviderData[size];
+ }
+ };
+
+ /**
+ * Builder for {@link CreateCredentialProviderData}.
+ *
+ * @hide
+ */
+ public static class Builder {
+ private @NonNull String mProviderFlattenedComponentName;
+ private @NonNull List<Entry> mSaveEntries = new ArrayList<>();
+ private @NonNull List<Entry> mActionChips = new ArrayList<>();
+ private boolean mIsDefaultProvider = false;
+ private @Nullable Entry mRemoteEntry = null;
+
+ /** Constructor with required properties. */
+ public Builder(@NonNull String providerFlattenedComponentName) {
+ mProviderFlattenedComponentName = providerFlattenedComponentName;
+ }
+
+ /** Sets the list of save credential entries to be displayed to the user. */
+ @NonNull
+ public Builder setSaveEntries(@NonNull List<Entry> credentialEntries) {
+ mSaveEntries = credentialEntries;
+ return this;
+ }
+
+ /** Sets the list of action chips to be displayed to the user. */
+ @NonNull
+ public Builder setActionChips(@NonNull List<Entry> actionChips) {
+ mActionChips = actionChips;
+ return this;
+ }
+
+ /** Sets whether this provider is the user's selected default provider. */
+ @NonNull
+ public Builder setIsDefaultProvider(boolean isDefaultProvider) {
+ mIsDefaultProvider = isDefaultProvider;
+ return this;
+ }
+
+ /** Builds a {@link CreateCredentialProviderData}. */
+ @NonNull
+ public CreateCredentialProviderData build() {
+ return new CreateCredentialProviderData(mProviderFlattenedComponentName,
+ mSaveEntries, mActionChips, mIsDefaultProvider, mRemoteEntry);
+ }
+ }
+}
diff --git a/core/java/android/credentials/ui/DisabledProviderData.java b/core/java/android/credentials/ui/DisabledProviderData.java
new file mode 100644
index 0000000..73c8dbe
--- /dev/null
+++ b/core/java/android/credentials/ui/DisabledProviderData.java
@@ -0,0 +1,60 @@
+/*
+ * 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.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Metadata of a disabled provider.
+ *
+ * @hide
+ */
+public class DisabledProviderData extends ProviderData implements Parcelable {
+
+ public DisabledProviderData(
+ @NonNull String providerFlattenedComponentName) {
+ super(providerFlattenedComponentName);
+ }
+
+ protected DisabledProviderData(@NonNull Parcel in) {
+ super(in);
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ super.writeToParcel(dest, flags);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ public static final @NonNull Creator<DisabledProviderData> CREATOR = new Creator<>() {
+ @Override
+ public DisabledProviderData createFromParcel(@NonNull Parcel in) {
+ return new DisabledProviderData(in);
+ }
+
+ @Override
+ public DisabledProviderData[] newArray(int size) {
+ return new DisabledProviderData[size];
+ }
+ };
+}
diff --git a/core/java/android/credentials/ui/GetCredentialProviderData.java b/core/java/android/credentials/ui/GetCredentialProviderData.java
new file mode 100644
index 0000000..834f9825
--- /dev/null
+++ b/core/java/android/credentials/ui/GetCredentialProviderData.java
@@ -0,0 +1,174 @@
+/*
+ * 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 android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.util.AnnotationValidations;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Per-provider metadata and entries for the get-credential flow.
+ *
+ * @hide
+ */
+public class GetCredentialProviderData extends ProviderData implements Parcelable {
+ @NonNull
+ private final List<Entry> mCredentialEntries;
+ @NonNull
+ private final List<Entry> mActionChips;
+ @Nullable
+ private final Entry mAuthenticationEntry;
+ @Nullable
+ private final Entry mRemoteEntry;
+
+ public GetCredentialProviderData(
+ @NonNull String providerFlattenedComponentName, @NonNull List<Entry> credentialEntries,
+ @NonNull List<Entry> actionChips, @Nullable Entry authenticationEntry,
+ @Nullable Entry remoteEntry) {
+ super(providerFlattenedComponentName);
+ mCredentialEntries = credentialEntries;
+ mActionChips = actionChips;
+ mAuthenticationEntry = authenticationEntry;
+ mRemoteEntry = remoteEntry;
+ }
+
+ @NonNull
+ public List<Entry> getCredentialEntries() {
+ return mCredentialEntries;
+ }
+
+ @NonNull
+ public List<Entry> getActionChips() {
+ return mActionChips;
+ }
+
+ @Nullable
+ public Entry getAuthenticationEntry() {
+ return mAuthenticationEntry;
+ }
+
+ @Nullable
+ public Entry getRemoteEntry() {
+ return mRemoteEntry;
+ }
+
+ protected GetCredentialProviderData(@NonNull Parcel in) {
+ super(in);
+
+ List<Entry> credentialEntries = new ArrayList<>();
+ in.readTypedList(credentialEntries, Entry.CREATOR);
+ mCredentialEntries = credentialEntries;
+ AnnotationValidations.validate(NonNull.class, null, mCredentialEntries);
+
+ List<Entry> actionChips = new ArrayList<>();
+ in.readTypedList(actionChips, Entry.CREATOR);
+ mActionChips = actionChips;
+ AnnotationValidations.validate(NonNull.class, null, mActionChips);
+
+ Entry authenticationEntry = in.readTypedObject(Entry.CREATOR);
+ mAuthenticationEntry = authenticationEntry;
+
+ Entry remoteEntry = in.readTypedObject(Entry.CREATOR);
+ mRemoteEntry = remoteEntry;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ super.writeToParcel(dest, flags);
+ dest.writeTypedList(mCredentialEntries);
+ dest.writeTypedList(mActionChips);
+ dest.writeTypedObject(mAuthenticationEntry, flags);
+ dest.writeTypedObject(mRemoteEntry, flags);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ public static final @NonNull Creator<GetCredentialProviderData> CREATOR =
+ new Creator<GetCredentialProviderData>() {
+ @Override
+ public GetCredentialProviderData createFromParcel(@NonNull Parcel in) {
+ return new GetCredentialProviderData(in);
+ }
+
+ @Override
+ public GetCredentialProviderData[] newArray(int size) {
+ return new GetCredentialProviderData[size];
+ }
+ };
+
+ /**
+ * Builder for {@link GetCredentialProviderData}.
+ *
+ * @hide
+ */
+ public static class Builder {
+ private @NonNull String mProviderFlattenedComponentName;
+ private @NonNull List<Entry> mCredentialEntries = new ArrayList<>();
+ private @NonNull List<Entry> mActionChips = new ArrayList<>();
+ private @Nullable Entry mAuthenticationEntry = null;
+ private @Nullable Entry mRemoteEntry = null;
+
+ /** Constructor with required properties. */
+ public Builder(@NonNull String providerFlattenedComponentName) {
+ mProviderFlattenedComponentName = providerFlattenedComponentName;
+ }
+
+ /** Sets the list of save / get credential entries to be displayed to the user. */
+ @NonNull
+ public Builder setCredentialEntries(@NonNull List<Entry> credentialEntries) {
+ mCredentialEntries = credentialEntries;
+ return this;
+ }
+
+ /** Sets the list of action chips to be displayed to the user. */
+ @NonNull
+ public Builder setActionChips(@NonNull List<Entry> actionChips) {
+ mActionChips = actionChips;
+ return this;
+ }
+
+ /** Sets the authentication entry to be displayed to the user. */
+ @NonNull
+ public Builder setAuthenticationEntry(@Nullable Entry authenticationEntry) {
+ mAuthenticationEntry = authenticationEntry;
+ return this;
+ }
+
+ /** Sets the remote entry to be displayed to the user. */
+ @NonNull
+ public Builder setRemoteEntry(@Nullable Entry remoteEntry) {
+ mRemoteEntry = remoteEntry;
+ return this;
+ }
+
+ /** Builds a {@link GetCredentialProviderData}. */
+ @NonNull
+ public GetCredentialProviderData build() {
+ return new GetCredentialProviderData(mProviderFlattenedComponentName,
+ mCredentialEntries, mActionChips, mAuthenticationEntry, mRemoteEntry);
+ }
+ }
+}
diff --git a/core/java/android/credentials/ui/IntentFactory.java b/core/java/android/credentials/ui/IntentFactory.java
index 1b70ea4..4751696 100644
--- a/core/java/android/credentials/ui/IntentFactory.java
+++ b/core/java/android/credentials/ui/IntentFactory.java
@@ -30,15 +30,20 @@
*/
public class IntentFactory {
/** Generate a new launch intent to the . */
- public static Intent newIntent(RequestInfo requestInfo,
- ArrayList<ProviderData> providerDataList, ResultReceiver resultReceiver) {
+ public static Intent newIntent(
+ RequestInfo requestInfo,
+ ArrayList<ProviderData> enabledProviderDataList,
+ ArrayList<DisabledProviderData> disabledProviderDataList,
+ ResultReceiver resultReceiver) {
Intent intent = new Intent();
// TODO: define these as proper config strings.
String activityName = "com.android.credentialmanager/.CredentialSelectorActivity";
intent.setComponent(ComponentName.unflattenFromString(activityName));
intent.putParcelableArrayListExtra(
- ProviderData.EXTRA_PROVIDER_DATA_LIST, providerDataList);
+ ProviderData.EXTRA_ENABLED_PROVIDER_DATA_LIST, enabledProviderDataList);
+ intent.putParcelableArrayListExtra(
+ ProviderData.EXTRA_DISABLED_PROVIDER_DATA_LIST, disabledProviderDataList);
intent.putExtra(RequestInfo.EXTRA_REQUEST_INFO, requestInfo);
intent.putExtra(Constants.EXTRA_RESULT_RECEIVER,
toIpcFriendlyResultReceiver(resultReceiver));
diff --git a/core/java/android/credentials/ui/ProviderData.java b/core/java/android/credentials/ui/ProviderData.java
index 3728469..eeaeb46 100644
--- a/core/java/android/credentials/ui/ProviderData.java
+++ b/core/java/android/credentials/ui/ProviderData.java
@@ -16,232 +16,62 @@
package android.credentials.ui;
-import android.annotation.CurrentTimeMillisLong;
import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.graphics.drawable.Icon;
import android.os.Parcel;
import android.os.Parcelable;
import com.android.internal.util.AnnotationValidations;
-import java.util.ArrayList;
-import java.util.List;
-
/**
- * Holds metadata and credential entries for a single provider.
+ * Super class for data structures that hold metadata and credential entries for a single provider.
*
* @hide
*/
-public class ProviderData implements Parcelable {
+public abstract class ProviderData implements Parcelable {
/**
- * The intent extra key for the list of {@code ProviderData} when launching the UX
- * activities.
+ * The intent extra key for the list of {@code ProviderData} from active providers when
+ * launching the UX activities.
*/
- public static final String EXTRA_PROVIDER_DATA_LIST =
- "android.credentials.ui.extra.PROVIDER_DATA_LIST";
+ public static final String EXTRA_ENABLED_PROVIDER_DATA_LIST =
+ "android.credentials.ui.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";
@NonNull
private final String mProviderFlattenedComponentName;
- @NonNull
- private final String mProviderDisplayName;
- @Nullable
- private final Icon mIcon;
- @NonNull
- private final List<Entry> mCredentialEntries;
- @NonNull
- private final List<Entry> mActionChips;
- @Nullable
- private final Entry mAuthenticationEntry;
-
- private final @CurrentTimeMillisLong long mLastUsedTimeMillis;
public ProviderData(
- @NonNull String providerFlattenedComponentName, @NonNull String providerDisplayName,
- @Nullable Icon icon, @NonNull List<Entry> credentialEntries,
- @NonNull List<Entry> actionChips, @Nullable Entry authenticationEntry,
- @CurrentTimeMillisLong long lastUsedTimeMillis) {
+ @NonNull String providerFlattenedComponentName) {
mProviderFlattenedComponentName = providerFlattenedComponentName;
- mProviderDisplayName = providerDisplayName;
- mIcon = icon;
- mCredentialEntries = credentialEntries;
- mActionChips = actionChips;
- mAuthenticationEntry = authenticationEntry;
- mLastUsedTimeMillis = lastUsedTimeMillis;
}
- /** Returns the unique provider id. */
+ /**
+ * Returns provider component name.
+ * It also serves as the unique identifier for this provider.
+ */
@NonNull
public String getProviderFlattenedComponentName() {
return mProviderFlattenedComponentName;
}
- @NonNull
- public String getProviderDisplayName() {
- return mProviderDisplayName;
- }
-
- @Nullable
- public Icon getIcon() {
- return mIcon;
- }
-
- @NonNull
- public List<Entry> getCredentialEntries() {
- return mCredentialEntries;
- }
-
- @NonNull
- public List<Entry> getActionChips() {
- return mActionChips;
- }
-
- @Nullable
- public Entry getAuthenticationEntry() {
- return mAuthenticationEntry;
- }
-
- /** Returns the time when the provider was last used. */
- public @CurrentTimeMillisLong long getLastUsedTimeMillis() {
- return mLastUsedTimeMillis;
- }
-
protected ProviderData(@NonNull Parcel in) {
String providerFlattenedComponentName = in.readString8();
mProviderFlattenedComponentName = providerFlattenedComponentName;
AnnotationValidations.validate(NonNull.class, null, mProviderFlattenedComponentName);
-
- String providerDisplayName = in.readString8();
- mProviderDisplayName = providerDisplayName;
- AnnotationValidations.validate(NonNull.class, null, mProviderDisplayName);
-
- Icon icon = in.readTypedObject(Icon.CREATOR);
- mIcon = icon;
-
- List<Entry> credentialEntries = new ArrayList<>();
- in.readTypedList(credentialEntries, Entry.CREATOR);
- mCredentialEntries = credentialEntries;
- AnnotationValidations.validate(NonNull.class, null, mCredentialEntries);
-
- List<Entry> actionChips = new ArrayList<>();
- in.readTypedList(actionChips, Entry.CREATOR);
- mActionChips = actionChips;
- AnnotationValidations.validate(NonNull.class, null, mActionChips);
-
- Entry authenticationEntry = in.readTypedObject(Entry.CREATOR);
- mAuthenticationEntry = authenticationEntry;
-
- long lastUsedTimeMillis = in.readLong();
- mLastUsedTimeMillis = lastUsedTimeMillis;
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeString8(mProviderFlattenedComponentName);
- dest.writeString8(mProviderDisplayName);
- dest.writeTypedObject(mIcon, flags);
- dest.writeTypedList(mCredentialEntries);
- dest.writeTypedList(mActionChips);
- dest.writeTypedObject(mAuthenticationEntry, flags);
- dest.writeLong(mLastUsedTimeMillis);
}
@Override
public int describeContents() {
return 0;
}
-
- public static final @NonNull Creator<ProviderData> CREATOR = new Creator<ProviderData>() {
- @Override
- public ProviderData createFromParcel(@NonNull Parcel in) {
- return new ProviderData(in);
- }
-
- @Override
- public ProviderData[] newArray(int size) {
- return new ProviderData[size];
- }
- };
-
- /**
- * Builder for {@link ProviderData}.
- *
- * @hide
- */
- public static class Builder {
- private @NonNull String mProviderFlattenedComponentName;
- private @NonNull String mProviderDisplayName;
- private @Nullable Icon mIcon;
- private @NonNull List<Entry> mCredentialEntries = new ArrayList<>();
- private @NonNull List<Entry> mActionChips = new ArrayList<>();
- private @Nullable Entry mAuthenticationEntry = null;
- private @CurrentTimeMillisLong long mLastUsedTimeMillis = 0L;
-
- /** Constructor with required properties. */
- public Builder(@NonNull String providerFlattenedComponentName,
- @NonNull String providerDisplayName,
- @Nullable Icon icon) {
- mProviderFlattenedComponentName = providerFlattenedComponentName;
- mProviderDisplayName = providerDisplayName;
- mIcon = icon;
- }
-
- /** Sets the unique provider id. */
- @NonNull
- public Builder setProviderFlattenedComponentName(@NonNull String providerFlattenedComponentName) {
- mProviderFlattenedComponentName = providerFlattenedComponentName;
- return this;
- }
-
- /** Sets the provider display name to be displayed to the user. */
- @NonNull
- public Builder setProviderDisplayName(@NonNull String providerDisplayName) {
- mProviderDisplayName = providerDisplayName;
- return this;
- }
-
- /** Sets the provider icon to be displayed to the user. */
- @NonNull
- public Builder setIcon(@NonNull Icon icon) {
- mIcon = icon;
- return this;
- }
-
- /** Sets the list of save / get credential entries to be displayed to the user. */
- @NonNull
- public Builder setCredentialEntries(@NonNull List<Entry> credentialEntries) {
- mCredentialEntries = credentialEntries;
- return this;
- }
-
- /** Sets the list of action chips to be displayed to the user. */
- @NonNull
- public Builder setActionChips(@NonNull List<Entry> actionChips) {
- mActionChips = actionChips;
- return this;
- }
-
- /** Sets the authentication entry to be displayed to the user. */
- @NonNull
- public Builder setAuthenticationEntry(@Nullable Entry authenticationEntry) {
- mAuthenticationEntry = authenticationEntry;
- return this;
- }
-
- /** Sets the time when the provider was last used. */
- @NonNull
- public Builder setLastUsedTimeMillis(@CurrentTimeMillisLong long lastUsedTimeMillis) {
- mLastUsedTimeMillis = lastUsedTimeMillis;
- return this;
- }
-
- /** Builds a {@link ProviderData}. */
- @NonNull
- public ProviderData build() {
- return new ProviderData(mProviderFlattenedComponentName, mProviderDisplayName,
- mIcon, mCredentialEntries,
- mActionChips, mAuthenticationEntry, mLastUsedTimeMillis);
- }
- }
}
diff --git a/core/java/android/credentials/ui/RequestInfo.java b/core/java/android/credentials/ui/RequestInfo.java
index 619b08e..59d5118 100644
--- a/core/java/android/credentials/ui/RequestInfo.java
+++ b/core/java/android/credentials/ui/RequestInfo.java
@@ -69,6 +69,7 @@
private final boolean mIsFirstUsage;
+ // TODO: change to package name
@NonNull
private final String mAppDisplayName;
diff --git a/core/java/android/hardware/radio/ProgramSelector.java b/core/java/android/hardware/radio/ProgramSelector.java
index 36ac1a0..8a92135 100644
--- a/core/java/android/hardware/radio/ProgramSelector.java
+++ b/core/java/android/hardware/radio/ProgramSelector.java
@@ -533,7 +533,6 @@
mProgramType = in.readInt();
mPrimaryId = in.readTypedObject(Identifier.CREATOR);
mSecondaryIds = in.createTypedArray(Identifier.CREATOR);
- Arrays.sort(mSecondaryIds);
if (Stream.of(mSecondaryIds).anyMatch(id -> id == null)) {
throw new IllegalArgumentException("secondaryIds list must not contain nulls");
}
diff --git a/core/java/android/inputmethodservice/IRemoteInputConnectionInvoker.java b/core/java/android/inputmethodservice/IRemoteInputConnectionInvoker.java
index 4f09bee..95aecfe 100644
--- a/core/java/android/inputmethodservice/IRemoteInputConnectionInvoker.java
+++ b/core/java/android/inputmethodservice/IRemoteInputConnectionInvoker.java
@@ -16,30 +16,29 @@
package android.inputmethodservice;
+import static android.view.inputmethod.TextBoundsInfoResult.CODE_CANCELLED;
+
import android.annotation.AnyThread;
import android.annotation.CallbackExecutor;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.graphics.RectF;
import android.os.Bundle;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.view.KeyEvent;
import android.view.inputmethod.CompletionInfo;
import android.view.inputmethod.CorrectionInfo;
-import android.view.inputmethod.DeleteGesture;
-import android.view.inputmethod.DeleteRangeGesture;
import android.view.inputmethod.ExtractedText;
import android.view.inputmethod.ExtractedTextRequest;
import android.view.inputmethod.HandwritingGesture;
import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputContentInfo;
-import android.view.inputmethod.InsertGesture;
-import android.view.inputmethod.JoinOrSplitGesture;
-import android.view.inputmethod.RemoveSpaceGesture;
-import android.view.inputmethod.SelectGesture;
-import android.view.inputmethod.SelectRangeGesture;
+import android.view.inputmethod.ParcelableHandwritingGesture;
import android.view.inputmethod.SurroundingText;
import android.view.inputmethod.TextAttribute;
+import android.view.inputmethod.TextBoundsInfo;
+import android.view.inputmethod.TextBoundsInfoResult;
import com.android.internal.infra.AndroidFuture;
import com.android.internal.inputmethod.IRemoteInputConnection;
@@ -47,6 +46,7 @@
import java.util.Objects;
import java.util.concurrent.Executor;
+import java.util.function.Consumer;
import java.util.function.IntConsumer;
/**
@@ -98,6 +98,44 @@
};
/**
+ * Subclass of {@link ResultReceiver} used by
+ * {@link #requestTextBoundsInfo(RectF, Executor, Consumer)} for providing
+ * callback.
+ */
+ private static final class TextBoundsInfoResultReceiver extends ResultReceiver {
+ @Nullable
+ private Consumer<TextBoundsInfoResult> mConsumer;
+ @Nullable
+ private Executor mExecutor;
+
+ TextBoundsInfoResultReceiver(@NonNull Executor executor,
+ @NonNull Consumer<TextBoundsInfoResult> consumer) {
+ super(null);
+ mExecutor = executor;
+ mConsumer = consumer;
+ }
+
+ @Override
+ protected void onReceiveResult(@TextBoundsInfoResult.ResultCode int resultCode,
+ @Nullable Bundle resultData) {
+ synchronized (this) {
+ if (mExecutor != null && mConsumer != null) {
+ final TextBoundsInfoResult textBoundsInfoResult = new TextBoundsInfoResult(
+ resultCode, TextBoundsInfo.createFromBundle(resultData));
+ mExecutor.execute(() -> mConsumer.accept(textBoundsInfoResult));
+ // provide callback only once.
+ clear();
+ }
+ }
+ }
+
+ private void clear() {
+ mExecutor = null;
+ mConsumer = null;
+ }
+ }
+
+ /**
* Creates a new instance of {@link IRemoteInputConnectionInvoker} for the given
* {@link IRemoteInputConnection}.
*
@@ -637,50 +675,19 @@
}
/**
- * Invokes one of {@link IRemoteInputConnection#performHandwritingSelectGesture},
- * {@link IRemoteInputConnection#performHandwritingSelectRangeGesture},
- * {@link IRemoteInputConnection#performHandwritingDeleteGesture},
- * {@link IRemoteInputConnection#performHandwritingDeleteRangeGesture},
- * {@link IRemoteInputConnection#performHandwritingInsertGesture},
- * {@link IRemoteInputConnection#performHandwritingRemoveSpaceGesture},
- * {@link IRemoteInputConnection#performHandwritingJoinOrSplitGesture}.
+ * Invokes {@link IRemoteInputConnection#performHandwritingGesture(
+ * InputConnectionCommandHeader, ParcelableHandwritingGesture, ResultReceiver)}.
*/
@AnyThread
- public void performHandwritingGesture(
- @NonNull HandwritingGesture gesture, @Nullable @CallbackExecutor Executor executor,
- @Nullable IntConsumer consumer) {
-
+ public void performHandwritingGesture(@NonNull ParcelableHandwritingGesture gesture,
+ @Nullable @CallbackExecutor Executor executor, @Nullable IntConsumer consumer) {
ResultReceiver resultReceiver = null;
if (consumer != null) {
Objects.requireNonNull(executor);
resultReceiver = new IntResultReceiver(executor, consumer);
}
try {
- if (gesture instanceof SelectGesture) {
- mConnection.performHandwritingSelectGesture(
- createHeader(), (SelectGesture) gesture, resultReceiver);
- } else if (gesture instanceof SelectRangeGesture) {
- mConnection.performHandwritingSelectRangeGesture(
- createHeader(), (SelectRangeGesture) gesture, resultReceiver);
- } else if (gesture instanceof InsertGesture) {
- mConnection.performHandwritingInsertGesture(
- createHeader(), (InsertGesture) gesture, resultReceiver);
- } else if (gesture instanceof DeleteGesture) {
- mConnection.performHandwritingDeleteGesture(
- createHeader(), (DeleteGesture) gesture, resultReceiver);
- } else if (gesture instanceof DeleteRangeGesture) {
- mConnection.performHandwritingDeleteRangeGesture(
- createHeader(), (DeleteRangeGesture) gesture, resultReceiver);
- } else if (gesture instanceof RemoveSpaceGesture) {
- mConnection.performHandwritingRemoveSpaceGesture(
- createHeader(), (RemoveSpaceGesture) gesture, resultReceiver);
- } else if (gesture instanceof JoinOrSplitGesture) {
- mConnection.performHandwritingJoinOrSplitGesture(
- createHeader(), (JoinOrSplitGesture) gesture, resultReceiver);
- } else if (consumer != null && executor != null) {
- executor.execute(()
- -> consumer.accept(InputConnection.HANDWRITING_GESTURE_RESULT_UNSUPPORTED));
- }
+ mConnection.performHandwritingGesture(createHeader(), gesture, resultReceiver);
} catch (RemoteException e) {
if (consumer != null && executor != null) {
executor.execute(() -> consumer.accept(
@@ -736,6 +743,28 @@
}
/**
+ * Invokes {@link IRemoteInputConnection#requestTextBoundsInfo(InputConnectionCommandHeader,
+ * RectF, ResultReceiver)}
+ * @param rectF {@code rectF} parameter to be passed.
+ * @param executor {@code Executor} parameter to be passed.
+ * @param consumer {@code Consumer} parameter to be passed.
+ */
+ @AnyThread
+ public void requestTextBoundsInfo(
+ @NonNull RectF rectF, @NonNull @CallbackExecutor Executor executor,
+ @NonNull Consumer<TextBoundsInfoResult> consumer) {
+ Objects.requireNonNull(executor);
+ Objects.requireNonNull(consumer);
+
+ final ResultReceiver resultReceiver = new TextBoundsInfoResultReceiver(executor, consumer);
+ try {
+ mConnection.requestTextBoundsInfo(createHeader(), rectF, resultReceiver);
+ } catch (RemoteException e) {
+ executor.execute(() -> consumer.accept(new TextBoundsInfoResult(CODE_CANCELLED)));
+ }
+ }
+
+ /**
* Invokes {@link IRemoteInputConnection#commitContent(InputConnectionCommandHeader,
* InputContentInfo, int, Bundle, AndroidFuture)}.
*
diff --git a/core/java/android/inputmethodservice/RemoteInputConnection.java b/core/java/android/inputmethodservice/RemoteInputConnection.java
index 09e86c4..976e71f 100644
--- a/core/java/android/inputmethodservice/RemoteInputConnection.java
+++ b/core/java/android/inputmethodservice/RemoteInputConnection.java
@@ -21,6 +21,7 @@
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.graphics.RectF;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
@@ -32,8 +33,10 @@
import android.view.inputmethod.HandwritingGesture;
import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputContentInfo;
+import android.view.inputmethod.ParcelableHandwritingGesture;
import android.view.inputmethod.SurroundingText;
import android.view.inputmethod.TextAttribute;
+import android.view.inputmethod.TextBoundsInfoResult;
import com.android.internal.inputmethod.CancellationGroup;
import com.android.internal.inputmethod.CompletableFutureUtil;
@@ -44,6 +47,7 @@
import java.lang.ref.WeakReference;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
+import java.util.function.Consumer;
import java.util.function.IntConsumer;
/**
@@ -418,7 +422,8 @@
public void performHandwritingGesture(
@NonNull HandwritingGesture gesture, @Nullable @CallbackExecutor Executor executor,
@Nullable IntConsumer consumer) {
- mInvoker.performHandwritingGesture(gesture, executor, consumer);
+ mInvoker.performHandwritingGesture(ParcelableHandwritingGesture.of(gesture), executor,
+ consumer);
}
@AnyThread
@@ -460,6 +465,13 @@
}
@AnyThread
+ public void requestTextBoundsInfo(
+ @NonNull RectF rectF, @NonNull @CallbackExecutor Executor executor,
+ @NonNull Consumer<TextBoundsInfoResult> consumer) {
+ mInvoker.requestTextBoundsInfo(rectF, executor, consumer);
+ }
+
+ @AnyThread
public Handler getHandler() {
// Nothing should happen when called from input method.
return null;
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index 2afa879..1673ade 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -561,9 +561,11 @@
*/
public final void recycle() {
if (mRecycled) {
- Log.w(TAG, "Recycle called on unowned Parcel. (recycle twice?) Here: "
+ Log.wtf(TAG, "Recycle called on unowned Parcel. (recycle twice?) Here: "
+ Log.getStackTraceString(new Throwable())
+ " Original recycle call (if DEBUG_RECYCLE): ", mStack);
+
+ return;
}
mRecycled = true;
diff --git a/core/java/android/os/Parcelable.java b/core/java/android/os/Parcelable.java
index 8a80457..a2b0486 100644
--- a/core/java/android/os/Parcelable.java
+++ b/core/java/android/os/Parcelable.java
@@ -188,7 +188,7 @@
* @return true if this parcelable is stable.
* @hide
*/
- @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ @SystemApi(client = SystemApi.Client.PRIVILEGED_APPS)
default @Stability int getStability() {
return PARCELABLE_STABILITY_LOCAL;
}
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 51dc643..f1879dd 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -1488,6 +1488,22 @@
public static final String KEY_RESTRICTIONS_PENDING = "restrictions_pending";
/**
+ * Specifies if a user is not allowed to use 2g networks.
+ *
+ * <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 all cases, the setting applies globally on the device and will prevent the device from
+ * scanning for or connecting to 2g networks, except in the case of an emergency.
+ *
+ * <p>The default value is <code>false</code>.
+ *
+ * @see DevicePolicyManager#addUserRestriction(ComponentName, String)
+ * @see DevicePolicyManager#clearUserRestriction(ComponentName, String)
+ * @see #getUserRestrictions()
+ */
+ public static final String DISALLOW_CELLULAR_2G = "no_cellular_2g";
+
+ /**
* 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
@@ -1568,6 +1584,7 @@
DISALLOW_SHARING_ADMIN_CONFIGURED_WIFI,
DISALLOW_WIFI_DIRECT,
DISALLOW_ADD_WIFI_CONFIG,
+ DISALLOW_CELLULAR_2G,
})
@Retention(RetentionPolicy.SOURCE)
public @interface UserRestrictionKey {}
diff --git a/core/java/android/service/autofill/FillRequest.java b/core/java/android/service/autofill/FillRequest.java
index b4010a4..0f7c9b6 100644
--- a/core/java/android/service/autofill/FillRequest.java
+++ b/core/java/android/service/autofill/FillRequest.java
@@ -111,6 +111,12 @@
*/
public static final @RequestFlags int FLAG_IME_SHOWING = 0x80;
+ /**
+ * Indicates whether autofill session should reset the fill dialog state.
+ * @hide
+ */
+ public static final @RequestFlags int FLAG_RESET_FILL_DIALOG_STATE = 0x100;
+
/** @hide */
public static final int INVALID_REQUEST_ID = Integer.MIN_VALUE;
@@ -208,7 +214,8 @@
FLAG_PASSWORD_INPUT_TYPE,
FLAG_VIEW_NOT_FOCUSED,
FLAG_SUPPORTS_FILL_DIALOG,
- FLAG_IME_SHOWING
+ FLAG_IME_SHOWING,
+ FLAG_RESET_FILL_DIALOG_STATE
})
@Retention(RetentionPolicy.SOURCE)
@DataClass.Generated.Member
@@ -236,6 +243,8 @@
return "FLAG_SUPPORTS_FILL_DIALOG";
case FLAG_IME_SHOWING:
return "FLAG_IME_SHOWING";
+ case FLAG_RESET_FILL_DIALOG_STATE:
+ return "FLAG_RESET_FILL_DIALOG_STATE";
default: return Integer.toHexString(value);
}
}
@@ -312,7 +321,8 @@
| FLAG_PASSWORD_INPUT_TYPE
| FLAG_VIEW_NOT_FOCUSED
| FLAG_SUPPORTS_FILL_DIALOG
- | FLAG_IME_SHOWING);
+ | FLAG_IME_SHOWING
+ | FLAG_RESET_FILL_DIALOG_STATE);
this.mInlineSuggestionsRequest = inlineSuggestionsRequest;
this.mDelayedFillIntentSender = delayedFillIntentSender;
@@ -473,7 +483,8 @@
| FLAG_PASSWORD_INPUT_TYPE
| FLAG_VIEW_NOT_FOCUSED
| FLAG_SUPPORTS_FILL_DIALOG
- | FLAG_IME_SHOWING);
+ | FLAG_IME_SHOWING
+ | FLAG_RESET_FILL_DIALOG_STATE);
this.mInlineSuggestionsRequest = inlineSuggestionsRequest;
this.mDelayedFillIntentSender = delayedFillIntentSender;
@@ -495,10 +506,10 @@
};
@DataClass.Generated(
- time = 1647856966565L,
+ time = 1663290803064L,
codegenVersion = "1.0.23",
sourceFile = "frameworks/base/core/java/android/service/autofill/FillRequest.java",
- inputSignatures = "public static final @android.service.autofill.FillRequest.RequestFlags int FLAG_MANUAL_REQUEST\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_COMPATIBILITY_MODE_REQUEST\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_PASSWORD_INPUT_TYPE\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_VIEW_NOT_FOCUSED\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_SUPPORTS_FILL_DIALOG\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_IME_SHOWING\npublic static final int INVALID_REQUEST_ID\nprivate final int mId\nprivate final @android.annotation.NonNull java.util.List<android.service.autofill.FillContext> mFillContexts\nprivate final @android.annotation.Nullable android.os.Bundle mClientState\nprivate final @android.service.autofill.FillRequest.RequestFlags int mFlags\nprivate final @android.annotation.Nullable android.view.inputmethod.InlineSuggestionsRequest mInlineSuggestionsRequest\nprivate final @android.annotation.Nullable android.content.IntentSender mDelayedFillIntentSender\nprivate void onConstructed()\nclass FillRequest extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genHiddenConstructor=true, genHiddenConstDefs=true)")
+ inputSignatures = "public static final @android.service.autofill.FillRequest.RequestFlags int FLAG_MANUAL_REQUEST\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_COMPATIBILITY_MODE_REQUEST\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_PASSWORD_INPUT_TYPE\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_VIEW_NOT_FOCUSED\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_SUPPORTS_FILL_DIALOG\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_IME_SHOWING\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_RESET_FILL_DIALOG_STATE\npublic static final int INVALID_REQUEST_ID\nprivate final int mId\nprivate final @android.annotation.NonNull java.util.List<android.service.autofill.FillContext> mFillContexts\nprivate final @android.annotation.Nullable android.os.Bundle mClientState\nprivate final @android.service.autofill.FillRequest.RequestFlags int mFlags\nprivate final @android.annotation.Nullable android.view.inputmethod.InlineSuggestionsRequest mInlineSuggestionsRequest\nprivate final @android.annotation.Nullable android.content.IntentSender mDelayedFillIntentSender\nprivate void onConstructed()\nclass FillRequest extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genHiddenConstructor=true, genHiddenConstDefs=true)")
@Deprecated
private void __metadata() {}
diff --git a/core/java/android/service/credentials/CredentialEntry.java b/core/java/android/service/credentials/CredentialEntry.java
index a3fa979..1d4ac25 100644
--- a/core/java/android/service/credentials/CredentialEntry.java
+++ b/core/java/android/service/credentials/CredentialEntry.java
@@ -172,9 +172,11 @@
* {@code credential}, or the {@code pendingIntent}.
*/
public @NonNull Builder setPendingIntent(@Nullable PendingIntent pendingIntent) {
- Preconditions.checkState(pendingIntent != null && mCredential != null,
- "credential is already set. Cannot set both the pendingIntent "
- + "and the credential");
+ if (pendingIntent != null) {
+ Preconditions.checkState(mCredential != null,
+ "credential is already set. Cannot set both the pendingIntent "
+ + "and the credential");
+ }
mPendingIntent = pendingIntent;
return this;
}
@@ -186,9 +188,11 @@
* the {@code pendingIntent}, or the {@code credential}.
*/
public @NonNull Builder setCredential(@Nullable Credential credential) {
- Preconditions.checkState(credential != null && mPendingIntent != null,
- "pendingIntent is already set. Cannot set both the "
- + "pendingIntent and the credential");
+ if (credential != null) {
+ Preconditions.checkState(mPendingIntent != null,
+ "pendingIntent is already set. Cannot set both the "
+ + "pendingIntent and the credential");
+ }
mCredential = credential;
return this;
}
diff --git a/core/java/android/service/credentials/SaveEntry.java b/core/java/android/service/credentials/SaveEntry.java
index abe51d4..55ff6ff 100644
--- a/core/java/android/service/credentials/SaveEntry.java
+++ b/core/java/android/service/credentials/SaveEntry.java
@@ -17,17 +17,11 @@
package android.service.credentials;
import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.app.PendingIntent;
import android.app.slice.Slice;
-import android.credentials.Credential;
import android.os.Parcel;
import android.os.Parcelable;
-import com.android.internal.util.Preconditions;
-
-import java.util.Objects;
-
/**
* An entry to be shown on the UI. This entry represents where the credential to be created will
* be stored. Examples include user's account, family group etc.
@@ -36,13 +30,11 @@
*/
public final class SaveEntry implements Parcelable {
private final @NonNull Slice mSlice;
- private final @Nullable PendingIntent mPendingIntent;
- private final @Nullable Credential mCredential;
+ private final @NonNull PendingIntent mPendingIntent;
private SaveEntry(@NonNull Parcel in) {
mSlice = in.readTypedObject(Slice.CREATOR);
mPendingIntent = in.readTypedObject(PendingIntent.CREATOR);
- mCredential = in.readTypedObject(Credential.CREATOR);
}
public static final @NonNull Creator<SaveEntry> CREATOR = new Creator<SaveEntry>() {
@@ -66,18 +58,23 @@
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeTypedObject(mSlice, flags);
dest.writeTypedObject(mPendingIntent, flags);
- dest.writeTypedObject(mCredential, flags);
}
- /* package-private */ SaveEntry(
+ /**
+ * Constructs a save entry to be displayed on the UI.
+ *
+ * @param slice the display content to be displayed on the UI, along with this entry
+ * @param pendingIntent the intent to be invoked when the user selects this entry
+ */
+ public SaveEntry(
@NonNull Slice slice,
- @Nullable PendingIntent pendingIntent,
- @Nullable Credential credential) {
+ @NonNull PendingIntent pendingIntent) {
this.mSlice = slice;
com.android.internal.util.AnnotationValidations.validate(
NonNull.class, null, mSlice);
this.mPendingIntent = pendingIntent;
- this.mCredential = credential;
+ com.android.internal.util.AnnotationValidations.validate(
+ NonNull.class, null, mPendingIntent);
}
/** Returns the content to be displayed with this save entry on the UI. */
@@ -86,76 +83,7 @@
}
/** Returns the pendingIntent to be invoked when this save entry on the UI is selectcd. */
- public @Nullable PendingIntent getPendingIntent() {
+ public @NonNull PendingIntent getPendingIntent() {
return mPendingIntent;
}
-
- /** Returns the credential produced by the {@link CreateCredentialRequest}. */
- public @Nullable Credential getCredential() {
- return mCredential;
- }
-
- /**
- * A builder for {@link SaveEntry}.
- */
- public static final class Builder {
-
- private @NonNull Slice mSlice;
- private @Nullable PendingIntent mPendingIntent;
- private @Nullable Credential mCredential;
-
- /**
- * Builds the instance.
- * @param slice the content to be displayed with this save entry
- *
- * @throws NullPointerException If {@code slice} is null.
- */
- public Builder(@NonNull Slice slice) {
- mSlice = Objects.requireNonNull(slice, "slice must not be null");
- }
-
- /**
- * Sets the pendingIntent to be invoked when this entry is selected by the user.
- *
- * @throws IllegalStateException If {@code credential} is already set. Must only set either
- * {@code credential}, or the {@code pendingIntent}.
- */
- public @NonNull Builder setPendingIntent(@Nullable PendingIntent pendingIntent) {
- Preconditions.checkState(pendingIntent != null
- && mCredential != null, "credential is already set. Must only set "
- + "either the pendingIntent or the credential");
- mPendingIntent = pendingIntent;
- return this;
- }
-
- /**
- * Sets the credential to be returned when this entry is selected by the user.
- *
- * @throws IllegalStateException If {@code pendingIntent} is already set. Must only
- * set either the {@code pendingIntent}, or {@code credential}.
- */
- public @NonNull Builder setCredential(@Nullable Credential credential) {
- Preconditions.checkState(credential != null && mPendingIntent != null,
- "pendingIntent is already set. Must only set either the credential "
- + "or the pendingIntent");
- mCredential = credential;
- return this;
- }
-
- /**
- * Builds the instance.
- *
- * @throws IllegalStateException if both {@code pendingIntent} and {@code credential}
- * are null.
- */
- public @NonNull SaveEntry build() {
- Preconditions.checkState(mPendingIntent == null && mCredential == null,
- "pendingIntent and credential both must not be null. Must set "
- + "either the pendingIntnet or the credential");
- return new SaveEntry(
- mSlice,
- mPendingIntent,
- mCredential);
- }
- }
}
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index c6cd708..37fc9f2 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -575,6 +575,7 @@
*/
public void reportEngineShown(boolean waitForEngineShown) {
if (mIWallpaperEngine.mShownReported) return;
+ Log.d(TAG, "reportEngineShown: shouldWait=" + waitForEngineShown);
if (!waitForEngineShown) {
Message message = mCaller.obtainMessage(MSG_REPORT_SHOWN);
mCaller.removeMessages(MSG_REPORT_SHOWN);
diff --git a/core/java/android/text/GraphemeClusterSegmentFinder.java b/core/java/android/text/GraphemeClusterSegmentFinder.java
index 3335751..656774f 100644
--- a/core/java/android/text/GraphemeClusterSegmentFinder.java
+++ b/core/java/android/text/GraphemeClusterSegmentFinder.java
@@ -49,6 +49,7 @@
@Override
public int previousStartBoundary(@IntRange(from = 0) int offset) {
+ if (offset == 0) return DONE;
int boundary = mTextPaint.getTextRunCursor(
mText, 0, mText.length(), false, offset, Paint.CURSOR_BEFORE);
return boundary == -1 ? DONE : boundary;
@@ -56,6 +57,7 @@
@Override
public int previousEndBoundary(@IntRange(from = 0) int offset) {
+ if (offset == 0) return DONE;
int boundary = mTextPaint.getTextRunCursor(
mText, 0, mText.length(), false, offset, Paint.CURSOR_BEFORE);
// Check that there is another cursor position before, otherwise this is not a valid
@@ -69,6 +71,7 @@
@Override
public int nextStartBoundary(@IntRange(from = 0) int offset) {
+ if (offset == mText.length()) return DONE;
int boundary = mTextPaint.getTextRunCursor(
mText, 0, mText.length(), false, offset, Paint.CURSOR_AFTER);
// Check that there is another cursor position after, otherwise this is not a valid
@@ -82,6 +85,7 @@
@Override
public int nextEndBoundary(@IntRange(from = 0) int offset) {
+ if (offset == mText.length()) return DONE;
int boundary = mTextPaint.getTextRunCursor(
mText, 0, mText.length(), false, offset, Paint.CURSOR_AFTER);
return boundary == -1 ? DONE : boundary;
diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java
index 1337d6a..54ec07e 100644
--- a/core/java/android/text/Layout.java
+++ b/core/java/android/text/Layout.java
@@ -3000,6 +3000,18 @@
}
/**
+ * Returns the BiDi level of this run.
+ *
+ * @param runIndex the index of the BiDi run
+ * @return the BiDi level of this run.
+ * @hide
+ */
+ @IntRange(from = 0)
+ public int getRunLevel(int runIndex) {
+ return (mDirections[runIndex * 2 + 1] >>> RUN_LEVEL_SHIFT) & RUN_LEVEL_MASK;
+ }
+
+ /**
* Returns true if the BiDi run is RTL.
*
* @param runIndex the index of the BiDi run
diff --git a/core/java/android/text/SegmentFinder.java b/core/java/android/text/SegmentFinder.java
index c21c577..be0094b 100644
--- a/core/java/android/text/SegmentFinder.java
+++ b/core/java/android/text/SegmentFinder.java
@@ -19,6 +19,13 @@
import android.annotation.IntRange;
import android.graphics.RectF;
+import androidx.annotation.NonNull;
+
+import com.android.internal.util.Preconditions;
+
+import java.util.Arrays;
+import java.util.Objects;
+
/**
* Finds text segment boundaries within text. Subclasses can implement different types of text
* segments. Grapheme clusters and words are examples of possible text segments. These are
@@ -63,4 +70,144 @@
* character offset, or {@code DONE} if there are none.
*/
public abstract int nextEndBoundary(@IntRange(from = 0) int offset);
+
+ /**
+ * The default {@link SegmentFinder} implementation based on given segment ranges.
+ */
+ public static class DefaultSegmentFinder extends SegmentFinder {
+ private final int[] mSegments;
+
+ /**
+ * Create a SegmentFinder with segments stored in an array, where i-th segment's start is
+ * stored at segments[2 * i] and end is stored at segments[2 * i + 1] respectively.
+ *
+ * <p> It is required that segments do not overlap, and are already sorted by their start
+ * indices. </p>
+ * @param segments the array that stores the segment ranges.
+ * @throws IllegalArgumentException if the given segments array's length is not even; the
+ * given segments are not sorted or there are segments overlap with others.
+ */
+ public DefaultSegmentFinder(@NonNull int[] segments) {
+ checkSegmentsValid(segments);
+ mSegments = segments;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int previousStartBoundary(@IntRange(from = 0) int offset) {
+ return findPrevious(offset, /* isStart = */ true);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int previousEndBoundary(@IntRange(from = 0) int offset) {
+ return findPrevious(offset, /* isStart = */ false);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int nextStartBoundary(@IntRange(from = 0) int offset) {
+ return findNext(offset, /* isStart = */ true);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int nextEndBoundary(@IntRange(from = 0) int offset) {
+ return findNext(offset, /* isStart = */ false);
+ }
+
+ private int findNext(int offset, boolean isStart) {
+ if (offset < 0) return DONE;
+ if (mSegments.length < 1 || offset > mSegments[mSegments.length - 1]) return DONE;
+
+ if (offset < mSegments[0]) {
+ return isStart ? mSegments[0] : mSegments[1];
+ }
+
+ int index = Arrays.binarySearch(mSegments, offset);
+ if (index >= 0) {
+ // mSegments may have duplicate elements (The previous segments end equals
+ // to the following segments start.) Move the index forwards since we are searching
+ // for the next segment.
+ if (index + 1 < mSegments.length && mSegments[index + 1] == offset) {
+ index = index + 1;
+ }
+ // Point the index to the first segment boundary larger than the given offset.
+ index += 1;
+ } else {
+ // binarySearch returns the insertion point, it's the first segment boundary larger
+ // than the given offset.
+ index = -(index + 1);
+ }
+ if (index >= mSegments.length) return DONE;
+
+ // +---------------------------------------+
+ // | | isStart | isEnd |
+ // |---------------+-----------+-----------|
+ // | indexIsStart | index | index + 1 |
+ // |---------------+-----------+-----------|
+ // | indexIsEnd | index + 1 | index |
+ // +---------------------------------------+
+ boolean indexIsStart = index % 2 == 0;
+ if (isStart != indexIsStart) {
+ return (index + 1 < mSegments.length) ? mSegments[index + 1] : DONE;
+ }
+ return mSegments[index];
+ }
+
+ private int findPrevious(int offset, boolean isStart) {
+ if (mSegments.length < 1 || offset < mSegments[0]) return DONE;
+
+ if (offset > mSegments[mSegments.length - 1]) {
+ return isStart ? mSegments[mSegments.length - 2] : mSegments[mSegments.length - 1];
+ }
+
+ int index = Arrays.binarySearch(mSegments, offset);
+ if (index >= 0) {
+ // mSegments may have duplicate elements (when the previous segments end equal
+ // to the following segments start). Move the index backwards since we are searching
+ // for the previous segment.
+ if (index > 0 && mSegments[index - 1] == offset) {
+ index = index - 1;
+ }
+ // Point the index to the first segment boundary smaller than the given offset.
+ index -= 1;
+ } else {
+ // binarySearch returns the insertion point, insertionPoint - 1 is the first
+ // segment boundary smaller than the given offset.
+ index = -(index + 1) - 1;
+ }
+ if (index < 0) return DONE;
+
+ // +---------------------------------------+
+ // | | isStart | isEnd |
+ // |---------------+-----------+-----------|
+ // | indexIsStart | index | index - 1 |
+ // |---------------+-----------+-----------|
+ // | indexIsEnd | index - 1 | index |
+ // +---------------------------------------+
+ boolean indexIsStart = index % 2 == 0;
+ if (isStart != indexIsStart) {
+ return (index > 0) ? mSegments[index - 1] : DONE;
+ }
+ return mSegments[index];
+ }
+
+ private static void checkSegmentsValid(int[] segments) {
+ Objects.requireNonNull(segments);
+ Preconditions.checkArgument(segments.length % 2 == 0,
+ "the length of segments must be even");
+ if (segments.length == 0) return;
+ int lastSegmentEnd = Integer.MIN_VALUE;
+ for (int index = 0; index < segments.length; index += 2) {
+ if (segments[index] < lastSegmentEnd) {
+ throw new IllegalArgumentException("segments can't overlap");
+ }
+ if (segments[index] >= segments[index + 1]) {
+ throw new IllegalArgumentException("the segment range can't be empty");
+ }
+ lastSegmentEnd = segments[index + 1];
+ }
+ }
+ }
}
diff --git a/core/java/android/text/TextUtils.java b/core/java/android/text/TextUtils.java
index 596e491..ff66e5f 100644
--- a/core/java/android/text/TextUtils.java
+++ b/core/java/android/text/TextUtils.java
@@ -2331,7 +2331,8 @@
return trimmed;
}
- private static boolean isNewline(int codePoint) {
+ /** @hide */
+ public static boolean isNewline(int codePoint) {
int type = Character.getType(codePoint);
return type == Character.PARAGRAPH_SEPARATOR || type == Character.LINE_SEPARATOR
|| codePoint == LINE_FEED_CODE_POINT;
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index d1f05ec..7b6a6d2 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -103,6 +103,25 @@
public static final String SETTINGS_NEW_KEYBOARD_UI = "settings_new_keyboard_ui";
/**
+ * Enable new shortcut list UI
+ * @hide
+ */
+ public static final String SETTINGS_NEW_KEYBOARD_SHORTCUT = "settings_new_keyboard_shortcut";
+
+ /**
+ * Enable new modifier key settings UI
+ * @hide
+ */
+ public static final String SETTINGS_NEW_KEYBOARD_MODIFIER_KEY =
+ "settings_new_keyboard_modifier_key";
+
+ /**
+ * Enable new trackpad settings UI
+ * @hide
+ */
+ public static final String SETTINGS_NEW_KEYBOARD_TRACKPAD = "settings_new_keyboard_trackpad";
+
+ /**
* Enable the new pages which is implemented with SPA.
* @hide
*/
@@ -143,6 +162,9 @@
DEFAULT_FLAGS.put(SETTINGS_HIDE_SECOND_LAYER_PAGE_NAVIGATE_UP_BUTTON_IN_TWO_PANE, "true");
DEFAULT_FLAGS.put(SETTINGS_AUTO_TEXT_WRAPPING, "false");
DEFAULT_FLAGS.put(SETTINGS_NEW_KEYBOARD_UI, "false");
+ DEFAULT_FLAGS.put(SETTINGS_NEW_KEYBOARD_SHORTCUT, "false");
+ DEFAULT_FLAGS.put(SETTINGS_NEW_KEYBOARD_MODIFIER_KEY, "false");
+ DEFAULT_FLAGS.put(SETTINGS_NEW_KEYBOARD_TRACKPAD, "false");
DEFAULT_FLAGS.put(SETTINGS_ENABLE_SPA, "false");
DEFAULT_FLAGS.put(SETTINGS_ADB_METRICS_WRITER, "false");
}
@@ -158,6 +180,9 @@
PERSISTENT_FLAGS.add(SETTINGS_HIDE_SECOND_LAYER_PAGE_NAVIGATE_UP_BUTTON_IN_TWO_PANE);
PERSISTENT_FLAGS.add(SETTINGS_AUTO_TEXT_WRAPPING);
PERSISTENT_FLAGS.add(SETTINGS_NEW_KEYBOARD_UI);
+ PERSISTENT_FLAGS.add(SETTINGS_NEW_KEYBOARD_SHORTCUT);
+ PERSISTENT_FLAGS.add(SETTINGS_NEW_KEYBOARD_MODIFIER_KEY);
+ PERSISTENT_FLAGS.add(SETTINGS_NEW_KEYBOARD_TRACKPAD);
}
/**
diff --git a/core/java/android/view/HandwritingDelegateConfiguration.java b/core/java/android/view/HandwritingDelegateConfiguration.java
new file mode 100644
index 0000000..719c614
--- /dev/null
+++ b/core/java/android/view/HandwritingDelegateConfiguration.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+import android.annotation.IdRes;
+import android.annotation.NonNull;
+
+/**
+ * Configuration for a view to act as a handwriting initiation delegate. This allows handwriting
+ * mode for a delegator editor view to be initiated by stylus movement on the delegate view.
+ *
+ * <p>If a stylus {@link MotionEvent} occurs within the delegate view's bounds, the callback
+ * returned by {@link #getInitiationCallback()} will be called. The callback implementation is
+ * expected to show and focus the delegator editor view. If a view with identifier matching {@link
+ * #getDelegatorViewId()} creates an input connection while the same stylus {@link MotionEvent}
+ * sequence is ongoing, handwriting mode will be initiated for that view.
+ *
+ * <p>A common use case is a custom view which looks like a text editor but does not actually
+ * support text editing itself, and clicking on the custom view causes an EditText to be shown. To
+ * support handwriting initiation in this case, {@link View#setHandwritingDelegateConfiguration} can
+ * be called on the custom view to configure it as a delegate, and set the EditText as the delegator
+ * by passing the EditText's identifier as the {@code delegatorViewId}. The {@code
+ * initiationCallback} implementation is typically the same as the click listener implementation
+ * which shows the EditText.
+ */
+public class HandwritingDelegateConfiguration {
+ @IdRes private final int mDelegatorViewId;
+ @NonNull private final Runnable mInitiationCallback;
+
+ /**
+ * Constructs a HandwritingDelegateConfiguration instance.
+ *
+ * @param delegatorViewId identifier of the delegator editor view for which handwriting mode
+ * should be initiated
+ * @param initiationCallback callback called when a stylus {@link MotionEvent} occurs within
+ * this view's bounds. This will be called from the UI thread.
+ */
+ public HandwritingDelegateConfiguration(
+ @IdRes int delegatorViewId, @NonNull Runnable initiationCallback) {
+ mDelegatorViewId = delegatorViewId;
+ mInitiationCallback = initiationCallback;
+ }
+
+ /**
+ * Returns the identifier of the delegator editor view for which handwriting mode should be
+ * initiated.
+ */
+ public int getDelegatorViewId() {
+ return mDelegatorViewId;
+ }
+
+ /**
+ * Returns the callback which should be called when a stylus {@link MotionEvent} occurs within
+ * the delegate view's bounds. The callback should only be called from the UI thread.
+ */
+ @NonNull
+ public Runnable getInitiationCallback() {
+ return mInitiationCallback;
+ }
+}
diff --git a/core/java/android/view/HandwritingInitiator.java b/core/java/android/view/HandwritingInitiator.java
index a0a07b3..2e4073e 100644
--- a/core/java/android/view/HandwritingInitiator.java
+++ b/core/java/android/view/HandwritingInitiator.java
@@ -16,6 +16,7 @@
package android.view;
+import android.annotation.IdRes;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.graphics.Rect;
@@ -161,6 +162,15 @@
if (candidateView != null) {
if (candidateView == getConnectedView()) {
startHandwriting(candidateView);
+ } else if (candidateView.getHandwritingDelegateConfiguration() != null) {
+ mState.mDelegatorViewId =
+ candidateView
+ .getHandwritingDelegateConfiguration()
+ .getDelegatorViewId();
+ candidateView
+ .getHandwritingDelegateConfiguration()
+ .getInitiationCallback()
+ .run();
} else {
if (candidateView.getRevealOnFocusHint()) {
candidateView.setRevealOnFocusHint(false);
@@ -259,8 +269,10 @@
}
final Rect handwritingArea = getViewHandwritingArea(connectedView);
- if (isInHandwritingArea(handwritingArea, mState.mStylusDownX,
- mState.mStylusDownY, connectedView)) {
+ if ((mState.mDelegatorViewId != View.NO_ID
+ && mState.mDelegatorViewId == connectedView.getId())
+ || isInHandwritingArea(
+ handwritingArea, mState.mStylusDownX, mState.mStylusDownY, connectedView)) {
startHandwriting(connectedView);
} else {
mState.mShouldInitHandwriting = false;
@@ -287,6 +299,11 @@
if (!view.isAutoHandwritingEnabled()) {
return false;
}
+ // The view may be a handwriting initiation delegate, in which case it is not the editor
+ // view for which handwriting would be started. However, in almost all cases, the return
+ // values of View#isStylusHandwritingAvailable will be the same for the delegate view and
+ // the delegator editor view. So the delegate view can be used to decide whether handwriting
+ // should be triggered.
return view.isStylusHandwritingAvailable();
}
@@ -473,6 +490,13 @@
* built InputConnection.
*/
private boolean mExceedHandwritingSlop;
+ /**
+ * If the current ongoing stylus MotionEvent sequence started over a handwriting initiation
+ * delegate view, then this is the view identifier of the corresponding delegator view. If
+ * the delegator view creates an input connection while the MotionEvent sequence is still
+ * ongoing, then handwriting mode will be initiated for the delegator view.
+ */
+ @IdRes private int mDelegatorViewId = View.NO_ID;
/** The pointer id of the stylus pointer that is being tracked. */
private final int mStylusPointerId;
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 198ac9d..b24303b 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -121,16 +121,23 @@
private static final boolean DEBUG = false;
private static final boolean DEBUG_POSITION = false;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(
+ maxTargetSdk = Build.VERSION_CODES.TIRAMISU,
+ publicAlternatives = "Track {@link SurfaceHolder#addCallback} instead")
final ArrayList<SurfaceHolder.Callback> mCallbacks = new ArrayList<>();
final int[] mLocation = new int[2];
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(
+ maxTargetSdk = Build.VERSION_CODES.TIRAMISU,
+ publicAlternatives = "Use {@link SurfaceHolder#lockCanvas} instead")
final ReentrantLock mSurfaceLock = new ReentrantLock();
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(
+ maxTargetSdk = Build.VERSION_CODES.TIRAMISU,
+ publicAlternatives = "Use {@link SurfaceHolder#getSurface} instead")
final Surface mSurface = new Surface(); // Current surface in use
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023,
+ publicAlternatives = "Use {@link View#getVisibility} instead")
boolean mDrawingStopped = true;
// We use this to track if the application has produced a frame
// in to the Surface. Up until that point, we should be careful not to punch
@@ -156,13 +163,16 @@
int mSubLayer = APPLICATION_MEDIA_SUBLAYER;
int mRequestedSubLayer = APPLICATION_MEDIA_SUBLAYER;
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023,
+ publicAlternatives = "Use {@link SurfaceHolder#isCreating} instead")
boolean mIsCreating = false;
private final ViewTreeObserver.OnScrollChangedListener mScrollChangedListener =
this::updateSurface;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(
+ maxTargetSdk = Build.VERSION_CODES.TIRAMISU,
+ publicAlternatives = "Rely on {@link ViewTreeObserver#dispatchOnPreDraw} instead")
private final ViewTreeObserver.OnPreDrawListener mDrawListener = () -> {
// reposition ourselves where the surface is
mHaveFrame = getWidth() > 0 && getHeight() > 0;
@@ -176,24 +186,32 @@
boolean mViewVisibility = false;
boolean mWindowStopped = false;
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023,
+ publicAlternatives = "Use {@link View#getWidth} instead")
int mRequestedWidth = -1;
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023,
+ publicAlternatives = "Use {@link View#getHeight} instead")
int mRequestedHeight = -1;
/* Set SurfaceView's format to 565 by default to maintain backward
* compatibility with applications assuming this format.
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(
+ maxTargetSdk = Build.VERSION_CODES.TIRAMISU,
+ publicAlternatives = "Use {@code SurfaceHolder.Callback#surfaceChanged} instead")
int mRequestedFormat = PixelFormat.RGB_565;
float mAlpha = 1f;
boolean mClipSurfaceToBounds;
int mBackgroundColor = Color.BLACK;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(
+ maxTargetSdk = Build.VERSION_CODES.TIRAMISU,
+ publicAlternatives = "Use {@link View#getWidth} and {@link View#getHeight} to "
+ + "determine if the SurfaceView is onscreen and has a frame")
boolean mHaveFrame = false;
boolean mSurfaceCreated = false;
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023,
+ publicAlternatives = "Time {@link SurfaceHolder#lockCanvas} instead")
long mLastLockTime = 0;
boolean mVisible = false;
@@ -202,9 +220,13 @@
int mSurfaceWidth = -1;
int mSurfaceHeight = -1;
float mCornerRadius;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(
+ maxTargetSdk = Build.VERSION_CODES.TIRAMISU,
+ publicAlternatives = "Use {@code SurfaceHolder.Callback#surfaceChanged} "
+ + "instead")
int mFormat = -1;
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023,
+ publicAlternatives = "Use {@link SurfaceHolder#getSurfaceFrame} instead")
final Rect mSurfaceFrame = new Rect();
int mLastSurfaceWidth = -1, mLastSurfaceHeight = -1;
@SurfaceControl.BufferTransform int mTransformHint = 0;
@@ -1410,7 +1432,9 @@
* @return true if the surface has dimensions that are fixed in size
* @hide
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(
+ maxTargetSdk = Build.VERSION_CODES.TIRAMISU,
+ publicAlternatives = "Track {@link SurfaceHolder#setFixedSize} instead")
public boolean isFixedSize() {
return (mRequestedWidth != -1 || mRequestedHeight != -1);
}
@@ -1446,7 +1470,9 @@
updateBackgroundColor(t);
}
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(
+ maxTargetSdk = Build.VERSION_CODES.TIRAMISU,
+ publicAlternatives = "Use {@link SurfaceView#getHolder} instead")
private final SurfaceHolder mSurfaceHolder = new SurfaceHolder() {
private static final String LOG_TAG = "SurfaceHolder";
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 7b6ebf7..49d9e67 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -5063,6 +5063,13 @@
private boolean mHoveringTouchDelegate = false;
/**
+ * Configuration for this view to act as a handwriting initiation delegate. This allows
+ * handwriting mode for a delegator editor view to be initiated by stylus movement on this
+ * delegate view.
+ */
+ private HandwritingDelegateConfiguration mHandwritingDelegateConfiguration;
+
+ /**
* Solid color to use as a background when creating the drawing cache. Enables
* the cache to use 16 bit bitmaps instead of 32 bit.
*/
@@ -12255,6 +12262,30 @@
}
/**
+ * Configures this view to act as a handwriting initiation delegate. This allows handwriting
+ * mode for a delegator editor view to be initiated by stylus movement on this delegate view.
+ *
+ * <p>If {@code null} is passed, this view will no longer act as a handwriting initiation
+ * delegate.
+ */
+ public void setHandwritingDelegateConfiguration(
+ @Nullable HandwritingDelegateConfiguration configuration) {
+ mHandwritingDelegateConfiguration = configuration;
+ if (configuration != null) {
+ setHandwritingArea(new Rect(0, 0, getWidth(), getHeight()));
+ }
+ }
+
+ /**
+ * If this view has been configured as a handwriting initiation delegate, returns the delegate
+ * configuration.
+ */
+ @Nullable
+ public HandwritingDelegateConfiguration getHandwritingDelegateConfiguration() {
+ return mHandwritingDelegateConfiguration;
+ }
+
+ /**
* Gets the coordinates of this view in the coordinate space of the
* {@link Surface} that contains the view.
*
@@ -24205,7 +24236,7 @@
}
}
rebuildOutline();
- if (onCheckIsTextEditor()) {
+ if (onCheckIsTextEditor() || mHandwritingDelegateConfiguration != null) {
setHandwritingArea(new Rect(0, 0, newWidth, newHeight));
}
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index ff4588a..e664ebf 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -1257,7 +1257,7 @@
mTmpFrames.attachedFrame = attachedFrame;
mTmpFrames.sizeCompatScale = sizeCompatScale[0];
mInvSizeCompatScale = 1f / sizeCompatScale[0];
- } catch (RemoteException e) {
+ } catch (RemoteException | RuntimeException e) {
mAdded = false;
mView = null;
mAttachInfo.mRootView = null;
diff --git a/core/java/android/view/accessibility/AccessibilityDisplayProxy.java b/core/java/android/view/accessibility/AccessibilityDisplayProxy.java
new file mode 100644
index 0000000..85f5056
--- /dev/null
+++ b/core/java/android/view/accessibility/AccessibilityDisplayProxy.java
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.accessibility;
+
+import android.accessibilityservice.AccessibilityGestureEvent;
+import android.accessibilityservice.AccessibilityService;
+import android.accessibilityservice.AccessibilityServiceInfo;
+import android.accessibilityservice.IAccessibilityServiceClient;
+import android.accessibilityservice.MagnificationConfig;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.content.Context;
+import android.graphics.Region;
+import android.os.IBinder;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.inputmethod.EditorInfo;
+
+import com.android.internal.inputmethod.IAccessibilityInputMethodSessionCallback;
+import com.android.internal.inputmethod.RemoteAccessibilityInputConnection;
+
+import java.util.List;
+import java.util.concurrent.Executor;
+
+/**
+ * Allows a privileged app - an app with MANAGE_ACCESSIBILITY permission and SystemAPI access - to
+ * interact with the windows in the display that this proxy represents. Proxying the default display
+ * or a display that is not tracked will throw an exception. Only the real user has access to global
+ * clients like SystemUI.
+ *
+ * <p>
+ * To register and unregister a proxy, use
+ * {@link AccessibilityManager#registerDisplayProxy(AccessibilityDisplayProxy)}
+ * and {@link AccessibilityManager#unregisterDisplayProxy(AccessibilityDisplayProxy)}. If the app
+ * that has registered the proxy dies, the system will remove the proxy.
+ *
+ * TODO(241429275): Complete proxy impl and add additional support (if necessary) like cache methods
+ * @hide
+ */
+@SystemApi
+public abstract class AccessibilityDisplayProxy {
+ private static final String LOG_TAG = "AccessibilityDisplayProxy";
+ private static final int INVALID_CONNECTION_ID = -1;
+
+ private List<AccessibilityServiceInfo> mInstalledAndEnabledServices;
+ private Executor mExecutor;
+ private int mConnectionId = INVALID_CONNECTION_ID;
+ private int mDisplayId;
+ IAccessibilityServiceClient mServiceClient;
+
+ /**
+ * Constructs an AccessibilityDisplayProxy instance.
+ * @param displayId the id of the display to proxy.
+ * @param executor the executor used to execute proxy callbacks.
+ * @param installedAndEnabledServices the list of infos representing the installed and
+ * enabled a11y services.
+ */
+ public AccessibilityDisplayProxy(int displayId, @NonNull Executor executor,
+ @NonNull List<AccessibilityServiceInfo> installedAndEnabledServices) {
+ mDisplayId = displayId;
+ mExecutor = executor;
+ // Typically, the context is the Service context of an accessibility service.
+ // Context is used for ResolveInfo check, which a proxy won't have, IME input
+ // (FLAG_INPUT_METHOD_EDITOR), which the proxy doesn't need, and tracing
+ // A11yInteractionClient methods.
+ // TODO(254097475): Enable tracing, potentially without exposing Context.
+ mServiceClient = new IAccessibilityServiceClientImpl(null, mExecutor);
+ mInstalledAndEnabledServices = installedAndEnabledServices;
+ }
+
+ /**
+ * Returns the id of the display being proxy-ed.
+ */
+ public int getDisplayId() {
+ return mDisplayId;
+ }
+
+ /**
+ * An IAccessibilityServiceClient that handles interrupts and accessibility events.
+ */
+ private class IAccessibilityServiceClientImpl extends
+ AccessibilityService.IAccessibilityServiceClientWrapper {
+
+ IAccessibilityServiceClientImpl(Context context, Executor executor) {
+ super(context, executor, new AccessibilityService.Callbacks() {
+ @Override
+ public void onAccessibilityEvent(AccessibilityEvent event) {
+ // TODO: call AccessiiblityProxy.onAccessibilityEvent
+ }
+
+ @Override
+ public void onInterrupt() {
+ // TODO: call AccessiiblityProxy.onInterrupt
+ }
+ @Override
+ public void onServiceConnected() {
+ // TODO: send service infos and call AccessiiblityProxy.onProxyConnected
+ }
+ @Override
+ public void init(int connectionId, IBinder windowToken) {
+ mConnectionId = connectionId;
+ }
+
+ @Override
+ public boolean onGesture(AccessibilityGestureEvent gestureInfo) {
+ return false;
+ }
+
+ @Override
+ public boolean onKeyEvent(KeyEvent event) {
+ return false;
+ }
+
+ @Override
+ public void onMagnificationChanged(int displayId, @NonNull Region region,
+ MagnificationConfig config) {
+ }
+
+ @Override
+ public void onMotionEvent(MotionEvent event) {
+ }
+
+ @Override
+ public void onTouchStateChanged(int displayId, int state) {
+ }
+
+ @Override
+ public void onSoftKeyboardShowModeChanged(int showMode) {
+ }
+
+ @Override
+ public void onPerformGestureResult(int sequence, boolean completedSuccessfully) {
+ }
+
+ @Override
+ public void onFingerprintCapturingGesturesChanged(boolean active) {
+ }
+
+ @Override
+ public void onFingerprintGesture(int gesture) {
+ }
+
+ @Override
+ public void onAccessibilityButtonClicked(int displayId) {
+ }
+
+ @Override
+ public void onAccessibilityButtonAvailabilityChanged(boolean available) {
+ }
+
+ @Override
+ public void onSystemActionsChanged() {
+ }
+
+ @Override
+ public void createImeSession(IAccessibilityInputMethodSessionCallback callback) {
+ }
+
+ @Override
+ public void startInput(@Nullable RemoteAccessibilityInputConnection inputConnection,
+ @NonNull EditorInfo editorInfo, boolean restarting) {
+ }
+ });
+ }
+ }
+}
diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java
index 5433fa0..423c560 100644
--- a/core/java/android/view/accessibility/AccessibilityManager.java
+++ b/core/java/android/view/accessibility/AccessibilityManager.java
@@ -1921,6 +1921,67 @@
}
}
+ /**
+ * Registers an {@link AccessibilityDisplayProxy}, so this proxy can access UI content specific
+ * to its display.
+ *
+ * @param proxy the {@link AccessibilityDisplayProxy} to register.
+ * @return {@code true} if the proxy is successfully registered.
+ *
+ * @throws IllegalArgumentException if the proxy's display is not currently tracked by a11y, is
+ * {@link android.view.Display#DEFAULT_DISPLAY}, is or lower than
+ * {@link android.view.Display#INVALID_DISPLAY}, or is already being proxy-ed.
+ *
+ * @throws SecurityException if the app does not hold the
+ * {@link Manifest.permission#MANAGE_ACCESSIBILITY} permission.
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.MANAGE_ACCESSIBILITY)
+ public boolean registerDisplayProxy(@NonNull AccessibilityDisplayProxy proxy) {
+ final IAccessibilityManager service;
+ synchronized (mLock) {
+ service = getServiceLocked();
+ if (service == null) {
+ return false;
+ }
+ }
+
+ try {
+ return service.registerProxyForDisplay(proxy.mServiceClient, proxy.getDisplayId());
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Unregisters an {@link AccessibilityDisplayProxy}.
+ *
+ * @return {@code true} if the proxy is successfully unregistered.
+ *
+ * @throws SecurityException if the app does not hold the
+ * {@link Manifest.permission#MANAGE_ACCESSIBILITY} permission.
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.MANAGE_ACCESSIBILITY)
+ public boolean unregisterDisplayProxy(@NonNull AccessibilityDisplayProxy proxy) {
+ final IAccessibilityManager service;
+ synchronized (mLock) {
+ service = getServiceLocked();
+ if (service == null) {
+ return false;
+ }
+ }
+ try {
+ return service.unregisterProxyForDisplay(proxy.getDisplayId());
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+
private IAccessibilityManager getServiceLocked() {
if (mService == null) {
tryConnectToServiceLocked(null);
diff --git a/core/java/android/view/accessibility/IAccessibilityManager.aidl b/core/java/android/view/accessibility/IAccessibilityManager.aidl
index 36fdcce4..a251948 100644
--- a/core/java/android/view/accessibility/IAccessibilityManager.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityManager.aidl
@@ -109,9 +109,9 @@
oneway void setAccessibilityWindowAttributes(int displayId, int windowId, int userId, in AccessibilityWindowAttributes attributes);
- // Requires Manifest.permission.MANAGE_ACCESSIBILITY
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MANAGE_ACCESSIBILITY)")
boolean registerProxyForDisplay(IAccessibilityServiceClient proxy, int displayId);
- // Requires Manifest.permission.MANAGE_ACCESSIBILITY
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MANAGE_ACCESSIBILITY)")
boolean unregisterProxyForDisplay(int displayId);
}
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 70cfc3e..ef683b7 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -19,6 +19,7 @@
import static android.service.autofill.FillRequest.FLAG_IME_SHOWING;
import static android.service.autofill.FillRequest.FLAG_MANUAL_REQUEST;
import static android.service.autofill.FillRequest.FLAG_PASSWORD_INPUT_TYPE;
+import static android.service.autofill.FillRequest.FLAG_RESET_FILL_DIALOG_STATE;
import static android.service.autofill.FillRequest.FLAG_SUPPORTS_FILL_DIALOG;
import static android.service.autofill.FillRequest.FLAG_VIEW_NOT_FOCUSED;
import static android.view.ContentInfo.SOURCE_AUTOFILL;
@@ -734,7 +735,7 @@
* Autofill will automatically trigger a fill request after activity
* start if there is any field is autofillable. But if there is a field that
* triggered autofill, it is unnecessary to trigger again through
- * AutofillManager#notifyViewEnteredForActivityStarted.
+ * AutofillManager#notifyViewEnteredForFillDialog.
*/
private AtomicBoolean mIsFillRequested;
@@ -747,6 +748,10 @@
private final String[] mFillDialogEnabledHints;
+ // Tracked all views that have appeared, including views that there are no
+ // dataset in responses. Used to avoid request pre-fill request again and again.
+ private final ArraySet<AutofillId> mAllTrackedViews = new ArraySet<>();
+
/** @hide */
public interface AutofillClient {
/**
@@ -1192,6 +1197,16 @@
* @hide
*/
public void notifyViewEnteredForFillDialog(View v) {
+ synchronized (mLock) {
+ if (mTrackedViews != null) {
+ // To support the fill dialog can show for the autofillable Views in
+ // different pages but in the same Activity. We need to reset the
+ // mIsFillRequested flag to allow asking for a new FillRequest when
+ // user switches to other page
+ mTrackedViews.checkViewState(v.getAutofillId());
+ }
+ }
+
// Skip if the fill request has been performed for a view.
if (mIsFillRequested.get()) {
return;
@@ -1318,6 +1333,10 @@
}
mForAugmentedAutofillOnly = false;
}
+
+ if ((flags & FLAG_SUPPORTS_FILL_DIALOG) != 0) {
+ flags |= FLAG_RESET_FILL_DIALOG_STATE;
+ }
updateSessionLocked(id, null, value, ACTION_VIEW_ENTERED, flags);
}
addEnteredIdLocked(id);
@@ -2217,6 +2236,7 @@
mIsFillRequested.set(false);
mShowAutofillDialogCalled = false;
mFillDialogTriggerIds = null;
+ mAllTrackedViews.clear();
if (resetEnteredIds) {
mEnteredIds = null;
}
@@ -2776,14 +2796,9 @@
+ ", mFillableIds=" + mFillableIds
+ ", mEnabled=" + mEnabled
+ ", mSessionId=" + mSessionId);
-
}
+
if (mEnabled && mSessionId == sessionId) {
- if (saveOnAllViewsInvisible) {
- mTrackedViews = new TrackedViews(trackedIds);
- } else {
- mTrackedViews = null;
- }
mSaveOnFinish = saveOnFinish;
if (fillableIds != null) {
if (mFillableIds == null) {
@@ -2805,6 +2820,27 @@
mSaveTriggerId = saveTriggerId;
setNotifyOnClickLocked(mSaveTriggerId, true);
}
+
+ if (!saveOnAllViewsInvisible) {
+ trackedIds = null;
+ }
+
+ final ArraySet<AutofillId> allFillableIds = new ArraySet<>();
+ if (mFillableIds != null) {
+ allFillableIds.addAll(mFillableIds);
+ }
+ if (trackedIds != null) {
+ for (AutofillId id : trackedIds) {
+ id.resetSessionId();
+ allFillableIds.add(id);
+ }
+ }
+
+ if (!allFillableIds.isEmpty()) {
+ mTrackedViews = new TrackedViews(trackedIds, Helper.toArray(allFillableIds));
+ } else {
+ mTrackedViews = null;
+ }
}
}
}
@@ -3576,10 +3612,19 @@
*/
private class TrackedViews {
/** Visible tracked views */
- @Nullable private ArraySet<AutofillId> mVisibleTrackedIds;
+ @NonNull private final ArraySet<AutofillId> mVisibleTrackedIds;
/** Invisible tracked views */
- @Nullable private ArraySet<AutofillId> mInvisibleTrackedIds;
+ @NonNull private final ArraySet<AutofillId> mInvisibleTrackedIds;
+
+ /** Visible tracked views for fill dialog */
+ @NonNull private final ArraySet<AutofillId> mVisibleDialogTrackedIds;
+
+ /** Invisible tracked views for fill dialog */
+ @NonNull private final ArraySet<AutofillId> mInvisibleDialogTrackedIds;
+
+ boolean mHasNewTrackedView;
+ boolean mIsTrackedSaveView;
/**
* Check if set is null or value is in set.
@@ -3645,43 +3690,65 @@
*
* @param trackedIds The views to be tracked
*/
- TrackedViews(@Nullable AutofillId[] trackedIds) {
- final AutofillClient client = getClient();
- if (!ArrayUtils.isEmpty(trackedIds) && client != null) {
- final boolean[] isVisible;
+ TrackedViews(@Nullable AutofillId[] trackedIds, @Nullable AutofillId[] allTrackedIds) {
+ mVisibleTrackedIds = new ArraySet<>();
+ mInvisibleTrackedIds = new ArraySet<>();
+ if (!ArrayUtils.isEmpty(trackedIds)) {
+ mIsTrackedSaveView = true;
+ initialTrackedViews(trackedIds, mVisibleTrackedIds, mInvisibleTrackedIds);
+ }
- if (client.autofillClientIsVisibleForAutofill()) {
- if (sVerbose) Log.v(TAG, "client is visible, check tracked ids");
- isVisible = client.autofillClientGetViewVisibility(trackedIds);
- } else {
- // All false
- isVisible = new boolean[trackedIds.length];
- }
-
- final int numIds = trackedIds.length;
- for (int i = 0; i < numIds; i++) {
- final AutofillId id = trackedIds[i];
- id.resetSessionId();
-
- if (isVisible[i]) {
- mVisibleTrackedIds = addToSet(mVisibleTrackedIds, id);
- } else {
- mInvisibleTrackedIds = addToSet(mInvisibleTrackedIds, id);
- }
- }
+ mVisibleDialogTrackedIds = new ArraySet<>();
+ mInvisibleDialogTrackedIds = new ArraySet<>();
+ if (!ArrayUtils.isEmpty(allTrackedIds)) {
+ initialTrackedViews(allTrackedIds, mVisibleDialogTrackedIds,
+ mInvisibleDialogTrackedIds);
+ mAllTrackedViews.addAll(Arrays.asList(allTrackedIds));
}
if (sVerbose) {
Log.v(TAG, "TrackedViews(trackedIds=" + Arrays.toString(trackedIds) + "): "
+ " mVisibleTrackedIds=" + mVisibleTrackedIds
- + " mInvisibleTrackedIds=" + mInvisibleTrackedIds);
+ + " mInvisibleTrackedIds=" + mInvisibleTrackedIds
+ + " allTrackedIds=" + Arrays.toString(allTrackedIds)
+ + " mVisibleDialogTrackedIds=" + mVisibleDialogTrackedIds
+ + " mInvisibleDialogTrackedIds=" + mInvisibleDialogTrackedIds);
}
- if (mVisibleTrackedIds == null) {
+ if (mIsTrackedSaveView && mVisibleTrackedIds.isEmpty()) {
finishSessionLocked(/* commitReason= */ COMMIT_REASON_VIEW_CHANGED);
}
}
+ private void initialTrackedViews(AutofillId[] trackedIds,
+ @NonNull ArraySet<AutofillId> visibleSet,
+ @NonNull ArraySet<AutofillId> invisibleSet) {
+ final boolean[] isVisible;
+ final AutofillClient client = getClient();
+ if (ArrayUtils.isEmpty(trackedIds) || client == null) {
+ return;
+ }
+ if (client.autofillClientIsVisibleForAutofill()) {
+ if (sVerbose) Log.v(TAG, "client is visible, check tracked ids");
+ isVisible = client.autofillClientGetViewVisibility(trackedIds);
+ } else {
+ // All false
+ isVisible = new boolean[trackedIds.length];
+ }
+
+ final int numIds = trackedIds.length;
+ for (int i = 0; i < numIds; i++) {
+ final AutofillId id = trackedIds[i];
+ id.resetSessionId();
+
+ if (isVisible[i]) {
+ addToSet(visibleSet, id);
+ } else {
+ addToSet(invisibleSet, id);
+ }
+ }
+ }
+
/**
* Called when a {@link View view's} visibility changes.
*
@@ -3698,22 +3765,37 @@
if (isClientVisibleForAutofillLocked()) {
if (isVisible) {
if (isInSet(mInvisibleTrackedIds, id)) {
- mInvisibleTrackedIds = removeFromSet(mInvisibleTrackedIds, id);
- mVisibleTrackedIds = addToSet(mVisibleTrackedIds, id);
+ removeFromSet(mInvisibleTrackedIds, id);
+ addToSet(mVisibleTrackedIds, id);
+ }
+ if (isInSet(mInvisibleDialogTrackedIds, id)) {
+ removeFromSet(mInvisibleDialogTrackedIds, id);
+ addToSet(mVisibleDialogTrackedIds, id);
}
} else {
if (isInSet(mVisibleTrackedIds, id)) {
- mVisibleTrackedIds = removeFromSet(mVisibleTrackedIds, id);
- mInvisibleTrackedIds = addToSet(mInvisibleTrackedIds, id);
+ removeFromSet(mVisibleTrackedIds, id);
+ addToSet(mInvisibleTrackedIds, id);
+ }
+ if (isInSet(mVisibleDialogTrackedIds, id)) {
+ removeFromSet(mVisibleDialogTrackedIds, id);
+ addToSet(mInvisibleDialogTrackedIds, id);
}
}
}
- if (mVisibleTrackedIds == null) {
+ if (mIsTrackedSaveView && mVisibleTrackedIds.isEmpty()) {
if (sVerbose) {
Log.v(TAG, "No more visible ids. Invisible = " + mInvisibleTrackedIds);
}
finishSessionLocked(/* commitReason= */ COMMIT_REASON_VIEW_CHANGED);
+
+ }
+ if (mVisibleDialogTrackedIds.isEmpty()) {
+ if (sVerbose) {
+ Log.v(TAG, "No more visible ids. Invisible = " + mInvisibleDialogTrackedIds);
+ }
+ processNoVisibleTrackedAllViews();
}
}
@@ -3727,66 +3809,66 @@
// The visibility of the views might have changed while the client was not be visible,
// hence update the visibility state for all views.
AutofillClient client = getClient();
- ArraySet<AutofillId> updatedVisibleTrackedIds = null;
- ArraySet<AutofillId> updatedInvisibleTrackedIds = null;
if (client != null) {
if (sVerbose) {
Log.v(TAG, "onVisibleForAutofillChangedLocked(): inv= " + mInvisibleTrackedIds
+ " vis=" + mVisibleTrackedIds);
}
- if (mInvisibleTrackedIds != null) {
- final ArrayList<AutofillId> orderedInvisibleIds =
- new ArrayList<>(mInvisibleTrackedIds);
- final boolean[] isVisible = client.autofillClientGetViewVisibility(
- Helper.toArray(orderedInvisibleIds));
- final int numInvisibleTrackedIds = orderedInvisibleIds.size();
- for (int i = 0; i < numInvisibleTrackedIds; i++) {
- final AutofillId id = orderedInvisibleIds.get(i);
- if (isVisible[i]) {
- updatedVisibleTrackedIds = addToSet(updatedVisibleTrackedIds, id);
-
- if (sDebug) {
- Log.d(TAG, "onVisibleForAutofill() " + id + " became visible");
- }
- } else {
- updatedInvisibleTrackedIds = addToSet(updatedInvisibleTrackedIds, id);
- }
- }
- }
-
- if (mVisibleTrackedIds != null) {
- final ArrayList<AutofillId> orderedVisibleIds =
- new ArrayList<>(mVisibleTrackedIds);
- final boolean[] isVisible = client.autofillClientGetViewVisibility(
- Helper.toArray(orderedVisibleIds));
-
- final int numVisibleTrackedIds = orderedVisibleIds.size();
- for (int i = 0; i < numVisibleTrackedIds; i++) {
- final AutofillId id = orderedVisibleIds.get(i);
-
- if (isVisible[i]) {
- updatedVisibleTrackedIds = addToSet(updatedVisibleTrackedIds, id);
- } else {
- updatedInvisibleTrackedIds = addToSet(updatedInvisibleTrackedIds, id);
-
- if (sDebug) {
- Log.d(TAG, "onVisibleForAutofill() " + id + " became invisible");
- }
- }
- }
- }
-
- mInvisibleTrackedIds = updatedInvisibleTrackedIds;
- mVisibleTrackedIds = updatedVisibleTrackedIds;
+ onVisibleForAutofillChangedInternalLocked(mVisibleTrackedIds, mInvisibleTrackedIds);
+ onVisibleForAutofillChangedInternalLocked(
+ mVisibleDialogTrackedIds, mInvisibleDialogTrackedIds);
}
- if (mVisibleTrackedIds == null) {
+ if (mIsTrackedSaveView && mVisibleTrackedIds.isEmpty()) {
if (sVerbose) {
- Log.v(TAG, "onVisibleForAutofillChangedLocked(): no more visible ids");
+ Log.v(TAG, "onVisibleForAutofillChangedLocked(): no more visible ids");
}
finishSessionLocked(/* commitReason= */ COMMIT_REASON_VIEW_CHANGED);
}
+ if (mVisibleDialogTrackedIds.isEmpty()) {
+ if (sVerbose) {
+ Log.v(TAG, "onVisibleForAutofillChangedLocked(): no more visible ids");
+ }
+ processNoVisibleTrackedAllViews();
+ }
+ }
+
+ void onVisibleForAutofillChangedInternalLocked(@NonNull ArraySet<AutofillId> visibleSet,
+ @NonNull ArraySet<AutofillId> invisibleSet) {
+ // The visibility of the views might have changed while the client was not be visible,
+ // hence update the visibility state for all views.
+ if (sVerbose) {
+ Log.v(TAG, "onVisibleForAutofillChangedLocked(): inv= " + invisibleSet
+ + " vis=" + visibleSet);
+ }
+
+ ArraySet<AutofillId> allTrackedIds = new ArraySet<>();
+ allTrackedIds.addAll(visibleSet);
+ allTrackedIds.addAll(invisibleSet);
+ if (!allTrackedIds.isEmpty()) {
+ visibleSet.clear();
+ invisibleSet.clear();
+ initialTrackedViews(Helper.toArray(allTrackedIds), visibleSet, invisibleSet);
+ }
+ }
+
+ private void processNoVisibleTrackedAllViews() {
+ mShowAutofillDialogCalled = false;
+ }
+
+ void checkViewState(AutofillId id) {
+ if (mAllTrackedViews.contains(id)) {
+ return;
+ }
+ // Add the id as tracked to avoid triggering fill request again and again.
+ mAllTrackedViews.add(id);
+ if (mHasNewTrackedView) {
+ return;
+ }
+ // First one new tracks view
+ mIsFillRequested.set(false);
+ mHasNewTrackedView = true;
}
}
diff --git a/core/java/android/view/contentcapture/ContentCaptureManager.java b/core/java/android/view/contentcapture/ContentCaptureManager.java
index 1664637..d067d4b 100644
--- a/core/java/android/view/contentcapture/ContentCaptureManager.java
+++ b/core/java/android/view/contentcapture/ContentCaptureManager.java
@@ -378,7 +378,7 @@
private final Object mLock = new Object();
@NonNull
- private final Context mContext;
+ private final StrippedContext mContext;
@NonNull
private final IContentCaptureManager mService;
@@ -414,9 +414,37 @@
}
/** @hide */
+ static class StrippedContext {
+ final String mPackageName;
+ final String mContext;
+ final @UserIdInt int mUserId;
+
+ private StrippedContext(Context context) {
+ mPackageName = context.getPackageName();
+ mContext = context.toString();
+ mUserId = context.getUserId();
+ }
+
+ @Override
+ public String toString() {
+ return mContext;
+ }
+
+ public String getPackageName() {
+ return mPackageName;
+ }
+
+ @UserIdInt
+ public int getUserId() {
+ return mUserId;
+ }
+ }
+
+ /** @hide */
public ContentCaptureManager(@NonNull Context context,
@NonNull IContentCaptureManager service, @NonNull ContentCaptureOptions options) {
- mContext = Objects.requireNonNull(context, "context cannot be null");
+ Objects.requireNonNull(context, "context cannot be null");
+ mContext = new StrippedContext(context);
mService = Objects.requireNonNull(service, "service cannot be null");
mOptions = Objects.requireNonNull(options, "options cannot be null");
diff --git a/core/java/android/view/contentcapture/MainContentCaptureSession.java b/core/java/android/view/contentcapture/MainContentCaptureSession.java
index c32ca9e..a989558 100644
--- a/core/java/android/view/contentcapture/MainContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/MainContentCaptureSession.java
@@ -36,7 +36,6 @@
import android.annotation.Nullable;
import android.annotation.UiThread;
import android.content.ComponentName;
-import android.content.Context;
import android.content.pm.ParceledListSlice;
import android.graphics.Insets;
import android.graphics.Rect;
@@ -103,7 +102,7 @@
private final AtomicBoolean mDisabled = new AtomicBoolean(false);
@NonNull
- private final Context mContext;
+ private final ContentCaptureManager.StrippedContext mContext;
@NonNull
private final ContentCaptureManager mManager;
@@ -197,7 +196,7 @@
}
}
- protected MainContentCaptureSession(@NonNull Context context,
+ protected MainContentCaptureSession(@NonNull ContentCaptureManager.StrippedContext context,
@NonNull ContentCaptureManager manager, @NonNull Handler handler,
@NonNull IContentCaptureManager systemServerInterface) {
mContext = context;
diff --git a/core/java/android/view/inputmethod/IInputMethodManagerGlobalInvoker.java b/core/java/android/view/inputmethod/IInputMethodManagerGlobalInvoker.java
index aeff37c..e8b1b46 100644
--- a/core/java/android/view/inputmethod/IInputMethodManagerGlobalInvoker.java
+++ b/core/java/android/view/inputmethod/IInputMethodManagerGlobalInvoker.java
@@ -16,6 +16,7 @@
package android.view.inputmethod;
+import android.Manifest;
import android.annotation.AnyThread;
import android.annotation.DurationMillisLong;
import android.annotation.NonNull;
@@ -106,8 +107,8 @@
* @param where where the information is coming from.
* @param exceptionHandler an optional {@link RemoteException} handler.
*/
- @RequiresNoPermission
@AnyThread
+ @RequiresNoPermission
static void startProtoDump(byte[] protoDump, int source, String where,
@Nullable Consumer<RemoteException> exceptionHandler) {
final IInputMethodManager service = getService();
@@ -126,8 +127,8 @@
*
* @param exceptionHandler an optional {@link RemoteException} handler.
*/
- @RequiresPermission(android.Manifest.permission.CONTROL_UI_TRACING)
@AnyThread
+ @RequiresPermission(Manifest.permission.CONTROL_UI_TRACING)
static void startImeTrace(@Nullable Consumer<RemoteException> exceptionHandler) {
final IInputMethodManager service = getService();
if (service == null) {
@@ -145,8 +146,8 @@
*
* @param exceptionHandler an optional {@link RemoteException} handler.
*/
- @RequiresPermission(android.Manifest.permission.CONTROL_UI_TRACING)
@AnyThread
+ @RequiresPermission(Manifest.permission.CONTROL_UI_TRACING)
static void stopImeTrace(@Nullable Consumer<RemoteException> exceptionHandler) {
final IInputMethodManager service = getService();
if (service == null) {
@@ -164,8 +165,8 @@
*
* @return The return value of {@link IInputMethodManager#isImeTraceEnabled()}.
*/
- @RequiresNoPermission
@AnyThread
+ @RequiresNoPermission
static boolean isImeTraceEnabled() {
final IInputMethodManager service = getService();
if (service == null) {
@@ -181,8 +182,8 @@
/**
* Invokes {@link IInputMethodManager#removeImeSurface()}
*/
- @RequiresPermission(android.Manifest.permission.INTERNAL_SYSTEM_WINDOW)
@AnyThread
+ @RequiresPermission(Manifest.permission.INTERNAL_SYSTEM_WINDOW)
static void removeImeSurface(@Nullable Consumer<RemoteException> exceptionHandler) {
final IInputMethodManager service = getService();
if (service == null) {
@@ -211,6 +212,7 @@
@AnyThread
@NonNull
+ @RequiresPermission(value = Manifest.permission.INTERACT_ACROSS_USERS_FULL, conditional = true)
static List<InputMethodInfo> getInputMethodList(@UserIdInt int userId,
@DirectBootAwareness int directBootAwareness) {
final IInputMethodManager service = getService();
@@ -226,6 +228,7 @@
@AnyThread
@NonNull
+ @RequiresPermission(value = Manifest.permission.INTERACT_ACROSS_USERS_FULL, conditional = true)
static List<InputMethodInfo> getEnabledInputMethodList(@UserIdInt int userId) {
final IInputMethodManager service = getService();
if (service == null) {
@@ -240,6 +243,7 @@
@AnyThread
@NonNull
+ @RequiresPermission(value = Manifest.permission.INTERACT_ACROSS_USERS_FULL, conditional = true)
static List<InputMethodSubtype> getEnabledInputMethodSubtypeList(@Nullable String imiId,
boolean allowsImplicitlyEnabledSubtypes, @UserIdInt int userId) {
final IInputMethodManager service = getService();
@@ -256,6 +260,7 @@
@AnyThread
@Nullable
+ @RequiresPermission(value = Manifest.permission.INTERACT_ACROSS_USERS_FULL, conditional = true)
static InputMethodSubtype getLastInputMethodSubtype(@UserIdInt int userId) {
final IInputMethodManager service = getService();
if (service == null) {
@@ -301,6 +306,7 @@
@AnyThread
@NonNull
+ @RequiresPermission(value = Manifest.permission.INTERACT_ACROSS_USERS_FULL, conditional = true)
static InputBindResult startInputOrWindowGainedFocus(@StartInputReason int startInputReason,
@NonNull IInputMethodClient client, @Nullable IBinder windowToken,
@StartInputFlags int startInputFlags,
@@ -339,6 +345,7 @@
}
@AnyThread
+ @RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS)
static void showInputMethodPickerFromSystem(@NonNull IInputMethodClient client,
int auxiliarySubtypeMode, int displayId) {
final IInputMethodManager service = getService();
@@ -353,6 +360,7 @@
}
@AnyThread
+ @RequiresPermission(Manifest.permission.TEST_INPUT_METHOD)
static boolean isInputMethodPickerShownForTest() {
final IInputMethodManager service = getService();
if (service == null) {
@@ -367,6 +375,7 @@
@AnyThread
@Nullable
+ @RequiresPermission(value = Manifest.permission.INTERACT_ACROSS_USERS_FULL, conditional = true)
static InputMethodSubtype getCurrentInputMethodSubtype(@UserIdInt int userId) {
final IInputMethodManager service = getService();
if (service == null) {
@@ -380,6 +389,7 @@
}
@AnyThread
+ @RequiresPermission(value = Manifest.permission.INTERACT_ACROSS_USERS_FULL, conditional = true)
static void setAdditionalInputMethodSubtypes(@NonNull String imeId,
@NonNull InputMethodSubtype[] subtypes, @UserIdInt int userId) {
final IInputMethodManager service = getService();
@@ -394,6 +404,7 @@
}
@AnyThread
+ @RequiresPermission(value = Manifest.permission.INTERACT_ACROSS_USERS_FULL, conditional = true)
static void setExplicitlyEnabledInputMethodSubtypes(@NonNull String imeId,
@NonNull int[] subtypeHashCodes, @UserIdInt int userId) {
final IInputMethodManager service = getService();
@@ -474,6 +485,7 @@
}
@AnyThread
+ @RequiresPermission(value = Manifest.permission.INTERACT_ACROSS_USERS_FULL, conditional = true)
static boolean isStylusHandwritingAvailableAsUser(@UserIdInt int userId) {
final IInputMethodManager service = getService();
if (service == null) {
@@ -487,6 +499,7 @@
}
@AnyThread
+ @RequiresPermission(Manifest.permission.TEST_INPUT_METHOD)
static void addVirtualStylusIdForTestSession(IInputMethodClient client) {
final IInputMethodManager service = getService();
if (service == null) {
@@ -500,6 +513,7 @@
}
@AnyThread
+ @RequiresPermission(Manifest.permission.TEST_INPUT_METHOD)
static void setStylusWindowIdleTimeoutForTest(
IInputMethodClient client, @DurationMillisLong long timeout) {
final IInputMethodManager service = getService();
diff --git a/core/java/android/view/inputmethod/InputConnection.java b/core/java/android/view/inputmethod/InputConnection.java
index 7d268a9..d6d7339 100644
--- a/core/java/android/view/inputmethod/InputConnection.java
+++ b/core/java/android/view/inputmethod/InputConnection.java
@@ -16,11 +16,14 @@
package android.view.inputmethod;
+import static android.view.inputmethod.TextBoundsInfoResult.CODE_UNSUPPORTED;
+
import android.annotation.CallbackExecutor;
import android.annotation.IntDef;
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.graphics.RectF;
import android.inputmethodservice.InputMethodService;
import android.os.Bundle;
import android.os.Handler;
@@ -32,7 +35,9 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
import java.util.concurrent.Executor;
+import java.util.function.Consumer;
import java.util.function.IntConsumer;
/**
@@ -1205,6 +1210,40 @@
return false;
}
+
+ /**
+ * Called by input method to request the {@link TextBoundsInfo} for a range of text which is
+ * covered by or in vicinity of the given {@code RectF}. It can be used as a supplementary
+ * method to implement the handwriting gesture API -
+ * {@link #performHandwritingGesture(HandwritingGesture, Executor, IntConsumer)}.
+ *
+ * <p><strong>Editor authors</strong>: It's preferred that the editor returns a
+ * {@link TextBoundsInfo} of all the text lines whose bounds intersect with the given
+ * {@code rectF}.
+ * </p>
+ *
+ * <p><strong>IME authors</strong>: This method is expensive when the text is long. Please
+ * consider that both the text bounds computation and IPC round-trip to send the data are time
+ * consuming. It's preferable to only request text bounds in smaller areas.
+ * </p>
+ *
+ * @param rectF the interested area where the text bounds are requested, in the screen
+ * coordinates.
+ * @param executor the executor to run the callback.
+ * @param consumer the callback invoked by editor to return the result. It must return a
+ * non-null object.
+ *
+ * @see TextBoundsInfo
+ * @see android.view.inputmethod.TextBoundsInfoResult
+ */
+ default void requestTextBoundsInfo(
+ @NonNull RectF rectF, @NonNull @CallbackExecutor Executor executor,
+ @NonNull Consumer<TextBoundsInfoResult> consumer) {
+ Objects.requireNonNull(executor);
+ Objects.requireNonNull(consumer);
+ executor.execute(() -> consumer.accept(new TextBoundsInfoResult(CODE_UNSUPPORTED)));
+ }
+
/**
* Called by the system to enable application developers to specify a dedicated thread on which
* {@link InputConnection} methods are called back.
diff --git a/core/java/android/view/inputmethod/InputConnectionWrapper.java b/core/java/android/view/inputmethod/InputConnectionWrapper.java
index 56beddf..7af96b6 100644
--- a/core/java/android/view/inputmethod/InputConnectionWrapper.java
+++ b/core/java/android/view/inputmethod/InputConnectionWrapper.java
@@ -20,6 +20,7 @@
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.graphics.RectF;
import android.os.Bundle;
import android.os.Handler;
import android.view.KeyEvent;
@@ -27,6 +28,7 @@
import com.android.internal.util.Preconditions;
import java.util.concurrent.Executor;
+import java.util.function.Consumer;
import java.util.function.IntConsumer;
/**
@@ -347,6 +349,17 @@
* @throws NullPointerException if the target is {@code null}.
*/
@Override
+ public void requestTextBoundsInfo(
+ @NonNull RectF rectF, @NonNull @CallbackExecutor Executor executor,
+ @NonNull Consumer<TextBoundsInfoResult> consumer) {
+ mTarget.requestTextBoundsInfo(rectF, executor, consumer);
+ }
+
+ /**
+ * {@inheritDoc}
+ * @throws NullPointerException if the target is {@code null}.
+ */
+ @Override
public Handler getHandler() {
return mTarget.getHandler();
}
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 53d77e1..514d909 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -16,8 +16,6 @@
package android.view.inputmethod;
-import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
-import static android.Manifest.permission.WRITE_SECURE_SETTINGS;
import static android.view.inputmethod.InputConnection.CURSOR_UPDATE_IMMEDIATE;
import static android.view.inputmethod.InputConnection.CURSOR_UPDATE_MONITOR;
import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.DISPLAY_ID;
@@ -1525,12 +1523,18 @@
/**
* Returns {@code true} if currently selected IME supports Stylus handwriting & is enabled for
* the given userId.
- * If the method returns {@code false}, {@link #startStylusHandwriting(View)} shouldn't be
- * called and Stylus touch should continue as normal touch input.
+ *
+ * <p>If the method returns {@code false}, {@link #startStylusHandwriting(View)} shouldn't be
+ * called and Stylus touch should continue as normal touch input.</p>
+ *
+ * <p>{@link Manifest.permission#INTERACT_ACROSS_USERS_FULL} is required when and only when
+ * {@code userId} is different from the user id of the current process.</p>
+ *
* @see #startStylusHandwriting(View)
* @param userId user ID to query.
* @hide
*/
+ @RequiresPermission(value = Manifest.permission.INTERACT_ACROSS_USERS_FULL, conditional = true)
public boolean isStylusHandwritingAvailableAsUser(@UserIdInt int userId) {
final Context fallbackContext = ActivityThread.currentApplication();
if (fallbackContext == null) {
@@ -1549,13 +1553,16 @@
/**
* Returns the list of installed input methods for the specified user.
*
+ * <p>{@link Manifest.permission#INTERACT_ACROSS_USERS_FULL} is required when and only when
+ * {@code userId} is different from the user id of the current process.</p>
+ *
* @param userId user ID to query
* @return {@link List} of {@link InputMethodInfo}.
* @hide
*/
@TestApi
- @RequiresPermission(INTERACT_ACROSS_USERS_FULL)
@NonNull
+ @RequiresPermission(value = Manifest.permission.INTERACT_ACROSS_USERS_FULL, conditional = true)
public List<InputMethodInfo> getInputMethodListAsUser(@UserIdInt int userId) {
return IInputMethodManagerGlobalInvoker.getInputMethodList(userId,
DirectBootAwareness.AUTO);
@@ -1564,14 +1571,17 @@
/**
* Returns the list of installed input methods for the specified user.
*
+ * <p>{@link Manifest.permission#INTERACT_ACROSS_USERS_FULL} is required when and only when
+ * {@code userId} is different from the user id of the current process.</p>
+ *
* @param userId user ID to query
* @param directBootAwareness {@code true} if caller want to query installed input methods list
* on user locked state.
* @return {@link List} of {@link InputMethodInfo}.
* @hide
*/
- @RequiresPermission(INTERACT_ACROSS_USERS_FULL)
@NonNull
+ @RequiresPermission(value = Manifest.permission.INTERACT_ACROSS_USERS_FULL, conditional = true)
public List<InputMethodInfo> getInputMethodListAsUser(@UserIdInt int userId,
@DirectBootAwareness int directBootAwareness) {
return IInputMethodManagerGlobalInvoker.getInputMethodList(userId, directBootAwareness);
@@ -1595,11 +1605,14 @@
/**
* Returns the list of enabled input methods for the specified user.
*
+ * <p>{@link Manifest.permission#INTERACT_ACROSS_USERS_FULL} is required when and only when
+ * {@code userId} is different from the user id of the current process.</p>
+ *
* @param userId user ID to query
* @return {@link List} of {@link InputMethodInfo}.
* @hide
*/
- @RequiresPermission(INTERACT_ACROSS_USERS_FULL)
+ @RequiresPermission(value = Manifest.permission.INTERACT_ACROSS_USERS_FULL, conditional = true)
public List<InputMethodInfo> getEnabledInputMethodListAsUser(@UserIdInt int userId) {
return IInputMethodManagerGlobalInvoker.getEnabledInputMethodList(userId);
}
@@ -1902,8 +1915,11 @@
* a result receiver: explicitly request that the current input method's
* soft input area be shown to the user, if needed.
*
- * @param view The currently focused view, which would like to receive
- * soft keyboard input.
+ * @param view The currently focused view, which would like to receive soft keyboard input.
+ * Note that this view is only considered focused here if both it itself has
+ * {@link View#isFocused view focus}, and its containing window has
+ * {@link View#hasWindowFocus window focus}. Otherwise the call fails and
+ * returns {@code false}.
* @param flags Provides additional operating flags. Currently may be
* 0 or have the {@link #SHOW_IMPLICIT} bit set.
*/
@@ -1965,8 +1981,11 @@
* can be garbage collected regardless of the lifetime of
* {@link ResultReceiver}.
*
- * @param view The currently focused view, which would like to receive
- * soft keyboard input.
+ * @param view The currently focused view, which would like to receive soft keyboard input.
+ * Note that this view is only considered focused here if both it itself has
+ * {@link View#isFocused view focus}, and its containing window has
+ * {@link View#hasWindowFocus window focus}. Otherwise the call fails and
+ * returns {@code false}.
* @param flags Provides additional operating flags. Currently may be
* 0 or have the {@link #SHOW_IMPLICIT} bit set.
* @param resultReceiver If non-null, this will be called by the IME when
@@ -2346,7 +2365,11 @@
* Starts an input connection from the served view that gains the window focus.
* Note that this method should *NOT* be called inside of {@code mH} lock to prevent start input
* background thread may blocked by other methods which already inside {@code mH} lock.
+ *
+ * <p>{@link Manifest.permission#INTERACT_ACROSS_USERS_FULL} is required when and only when
+ * {@code userId} is different from the user id of the current process.</p>
*/
+ @RequiresPermission(value = Manifest.permission.INTERACT_ACROSS_USERS_FULL, conditional = true)
private boolean startInputInner(@StartInputReason int startInputReason,
@Nullable IBinder windowGainingFocus, @StartInputFlags int startInputFlags,
@SoftInputModeFlags int softInputMode, int windowFlags) {
@@ -2590,6 +2613,7 @@
* @hide
*/
@TestApi
+ @RequiresPermission(Manifest.permission.TEST_INPUT_METHOD)
public void addVirtualStylusIdForTestSession() {
synchronized (mH) {
IInputMethodManagerGlobalInvoker.addVirtualStylusIdForTestSession(mClient);
@@ -2602,8 +2626,8 @@
* @param timeout to set in milliseconds. To reset to default, use a value <= zero.
* @hide
*/
- @RequiresPermission(Manifest.permission.TEST_INPUT_METHOD)
@TestApi
+ @RequiresPermission(Manifest.permission.TEST_INPUT_METHOD)
public void setStylusWindowIdleTimeoutForTest(@DurationMillisLong long timeout) {
synchronized (mH) {
IInputMethodManagerGlobalInvoker.setStylusWindowIdleTimeoutForTest(mClient, timeout);
@@ -3082,7 +3106,7 @@
*
* <p>On Android {@link Build.VERSION_CODES#Q} and later devices, the undocumented behavior that
* token can be {@code null} when the caller has
- * {@link android.Manifest.permission#WRITE_SECURE_SETTINGS} is deprecated. Instead, update
+ * {@link Manifest.permission#WRITE_SECURE_SETTINGS} is deprecated. Instead, update
* {@link android.provider.Settings.Secure#DEFAULT_INPUT_METHOD} and
* {@link android.provider.Settings.Secure#SELECTED_INPUT_METHOD_SUBTYPE} directly.</p>
*
@@ -3114,7 +3138,7 @@
if (fallbackContext == null) {
return;
}
- if (fallbackContext.checkSelfPermission(WRITE_SECURE_SETTINGS)
+ if (fallbackContext.checkSelfPermission(Manifest.permission.WRITE_SECURE_SETTINGS)
!= PackageManager.PERMISSION_GRANTED) {
return;
}
@@ -3151,7 +3175,7 @@
* from an application or a service which has a token of the currently active input method.
*
* <p>On Android {@link Build.VERSION_CODES#Q} and later devices, {@code token} cannot be
- * {@code null} even with {@link android.Manifest.permission#WRITE_SECURE_SETTINGS}. Instead,
+ * {@code null} even with {@link Manifest.permission#WRITE_SECURE_SETTINGS}. Instead,
* update {@link android.provider.Settings.Secure#DEFAULT_INPUT_METHOD} and
* {@link android.provider.Settings.Secure#SELECTED_INPUT_METHOD_SUBTYPE} directly.</p>
*
@@ -3433,7 +3457,7 @@
* @param displayId The ID of the display where the chooser dialog should be shown.
* @hide
*/
- @RequiresPermission(WRITE_SECURE_SETTINGS)
+ @RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS)
public void showInputMethodPickerFromSystem(boolean showAuxiliarySubtypes, int displayId) {
final int mode = showAuxiliarySubtypes
? SHOW_IM_PICKER_MODE_INCLUDE_AUXILIARY_SUBTYPES
@@ -3459,6 +3483,7 @@
* @hide
*/
@TestApi
+ @RequiresPermission(Manifest.permission.TEST_INPUT_METHOD)
public boolean isInputMethodPickerShown() {
return IInputMethodManagerGlobalInvoker.isInputMethodPickerShownForTest();
}
@@ -3511,11 +3536,11 @@
* {@link InputMethodService#switchInputMethod(String, InputMethodSubtype)}, which
* does not require any permission as long as the caller is the current IME.
* If the calling process is some privileged app that already has
- * {@link android.Manifest.permission#WRITE_SECURE_SETTINGS} permission, just
+ * {@link Manifest.permission#WRITE_SECURE_SETTINGS} permission, just
* directly update {@link Settings.Secure#SELECTED_INPUT_METHOD_SUBTYPE}.
*/
@Deprecated
- @RequiresPermission(WRITE_SECURE_SETTINGS)
+ @RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS)
public boolean setCurrentInputMethodSubtype(InputMethodSubtype subtype) {
if (Process.myUid() == Process.SYSTEM_UID) {
Log.w(TAG, "System process should not call setCurrentInputMethodSubtype() because "
@@ -3532,7 +3557,7 @@
if (fallbackContext == null) {
return false;
}
- if (fallbackContext.checkSelfPermission(WRITE_SECURE_SETTINGS)
+ if (fallbackContext.checkSelfPermission(Manifest.permission.WRITE_SECURE_SETTINGS)
!= PackageManager.PERMISSION_GRANTED) {
return false;
}
diff --git a/core/java/android/view/inputmethod/InputMethodManagerGlobal.java b/core/java/android/view/inputmethod/InputMethodManagerGlobal.java
index 63d9167..5df9fd1 100644
--- a/core/java/android/view/inputmethod/InputMethodManagerGlobal.java
+++ b/core/java/android/view/inputmethod/InputMethodManagerGlobal.java
@@ -16,6 +16,7 @@
package android.view.inputmethod;
+import android.Manifest;
import android.annotation.AnyThread;
import android.annotation.Nullable;
import android.annotation.RequiresNoPermission;
@@ -51,8 +52,8 @@
* @param where where the information is coming from.
* @param exceptionHandler an optional {@link RemoteException} handler.
*/
- @RequiresNoPermission
@AnyThread
+ @RequiresNoPermission
public static void startProtoDump(byte[] protoDump, int source, String where,
@Nullable Consumer<RemoteException> exceptionHandler) {
IInputMethodManagerGlobalInvoker.startProtoDump(protoDump, source, where, exceptionHandler);
@@ -63,8 +64,8 @@
*
* @param exceptionHandler an optional {@link RemoteException} handler.
*/
- @RequiresPermission(android.Manifest.permission.CONTROL_UI_TRACING)
@AnyThread
+ @RequiresPermission(Manifest.permission.CONTROL_UI_TRACING)
public static void startImeTrace(@Nullable Consumer<RemoteException> exceptionHandler) {
IInputMethodManagerGlobalInvoker.startImeTrace(exceptionHandler);
}
@@ -74,8 +75,8 @@
*
* @param exceptionHandler an optional {@link RemoteException} handler.
*/
- @RequiresPermission(android.Manifest.permission.CONTROL_UI_TRACING)
@AnyThread
+ @RequiresPermission(Manifest.permission.CONTROL_UI_TRACING)
public static void stopImeTrace(@Nullable Consumer<RemoteException> exceptionHandler) {
IInputMethodManagerGlobalInvoker.stopImeTrace(exceptionHandler);
}
@@ -85,8 +86,8 @@
*
* @return The return value of {@link IInputMethodManager#isImeTraceEnabled()}.
*/
- @RequiresNoPermission
@AnyThread
+ @RequiresNoPermission
public static boolean isImeTraceEnabled() {
return IInputMethodManagerGlobalInvoker.isImeTraceEnabled();
}
@@ -96,8 +97,8 @@
*
* @param exceptionHandler an optional {@link RemoteException} handler.
*/
- @RequiresPermission(android.Manifest.permission.INTERNAL_SYSTEM_WINDOW)
@AnyThread
+ @RequiresPermission(Manifest.permission.INTERNAL_SYSTEM_WINDOW)
public static void removeImeSurface(@Nullable Consumer<RemoteException> exceptionHandler) {
IInputMethodManagerGlobalInvoker.removeImeSurface(exceptionHandler);
}
diff --git a/core/java/android/view/inputmethod/InsertGesture.java b/core/java/android/view/inputmethod/InsertGesture.java
index 9f03289..0449a16 100644
--- a/core/java/android/view/inputmethod/InsertGesture.java
+++ b/core/java/android/view/inputmethod/InsertGesture.java
@@ -21,7 +21,6 @@
import android.graphics.PointF;
import android.os.Parcel;
import android.os.Parcelable;
-import android.text.TextUtils;
import android.widget.TextView;
import androidx.annotation.Nullable;
@@ -52,7 +51,8 @@
mPoint = source.readTypedObject(PointF.CREATOR);
}
- /** Returns the text that will be inserted at {@link #getInsertionPoint()} **/
+ /** Returns the text that will be inserted at {@link #getInsertionPoint()}. When text is
+ * empty, cursor should be moved the insertion point. **/
@NonNull
public String getTextToInsert() {
return mTextToInsert;
@@ -75,7 +75,11 @@
private PointF mPoint;
private String mFallbackText;
- /** set the text that will be inserted at {@link #setInsertionPoint(PointF)} **/
+ /**
+ * Set the text that will be inserted at {@link #setInsertionPoint(PointF)}. When set with
+ * an empty string, cursor will be moved to {@link #getInsertionPoint()} and no text
+ * would be inserted.
+ */
@NonNull
@SuppressLint("MissingGetterMatchingBuilder")
public Builder setTextToInsert(@NonNull String text) {
@@ -114,8 +118,8 @@
if (mPoint == null) {
throw new IllegalArgumentException("Insertion point must be set.");
}
- if (TextUtils.isEmpty(mText)) {
- throw new IllegalArgumentException("Text to insert must be non-empty.");
+ if (mText == null) {
+ throw new IllegalArgumentException("Text to insert must be set.");
}
return new InsertGesture(mText, mPoint, mFallbackText);
}
diff --git a/core/java/android/view/inputmethod/ParcelableHandwritingGesture.aidl b/core/java/android/view/inputmethod/ParcelableHandwritingGesture.aidl
new file mode 100644
index 0000000..ffadf82
--- /dev/null
+++ b/core/java/android/view/inputmethod/ParcelableHandwritingGesture.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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.view.inputmethod;
+
+parcelable ParcelableHandwritingGesture;
diff --git a/core/java/android/view/inputmethod/ParcelableHandwritingGesture.java b/core/java/android/view/inputmethod/ParcelableHandwritingGesture.java
new file mode 100644
index 0000000..e4066fc
--- /dev/null
+++ b/core/java/android/view/inputmethod/ParcelableHandwritingGesture.java
@@ -0,0 +1,109 @@
+/*
+ * 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.view.inputmethod;
+
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Objects;
+
+/**
+ * A generic container of parcelable {@link HandwritingGesture}.
+ *
+ * @hide
+ */
+public final class ParcelableHandwritingGesture implements Parcelable {
+ @NonNull
+ private final HandwritingGesture mGesture;
+ @NonNull
+ private final Parcelable mGestureAsParcelable;
+
+ private ParcelableHandwritingGesture(@NonNull HandwritingGesture gesture) {
+ mGesture = gesture;
+ // For fail-fast.
+ mGestureAsParcelable = (Parcelable) gesture;
+ }
+
+ /**
+ * Creates {@link ParcelableHandwritingGesture} from {@link HandwritingGesture}, which also
+ * implements {@link Parcelable}.
+ *
+ * @param gesture {@link HandwritingGesture} object to be stored.
+ * @return {@link ParcelableHandwritingGesture} to be stored in {@link Parcel}.
+ */
+ @NonNull
+ public static ParcelableHandwritingGesture of(@NonNull HandwritingGesture gesture) {
+ return new ParcelableHandwritingGesture(Objects.requireNonNull(gesture));
+ }
+
+ /**
+ * @return {@link HandwritingGesture} object stored in this container.
+ */
+ @NonNull
+ public HandwritingGesture get() {
+ return mGesture;
+ }
+
+ private static HandwritingGesture createFromParcelInternal(
+ @HandwritingGesture.GestureType int gestureType, @NonNull Parcel parcel) {
+ switch (gestureType) {
+ case HandwritingGesture.GESTURE_TYPE_NONE:
+ throw new UnsupportedOperationException("GESTURE_TYPE_NONE is not supported");
+ case HandwritingGesture.GESTURE_TYPE_SELECT:
+ return SelectGesture.CREATOR.createFromParcel(parcel);
+ case HandwritingGesture.GESTURE_TYPE_SELECT_RANGE:
+ return SelectRangeGesture.CREATOR.createFromParcel(parcel);
+ case HandwritingGesture.GESTURE_TYPE_INSERT:
+ return InsertGesture.CREATOR.createFromParcel(parcel);
+ case HandwritingGesture.GESTURE_TYPE_DELETE:
+ return DeleteGesture.CREATOR.createFromParcel(parcel);
+ case HandwritingGesture.GESTURE_TYPE_DELETE_RANGE:
+ return DeleteRangeGesture.CREATOR.createFromParcel(parcel);
+ case HandwritingGesture.GESTURE_TYPE_JOIN_OR_SPLIT:
+ return JoinOrSplitGesture.CREATOR.createFromParcel(parcel);
+ case HandwritingGesture.GESTURE_TYPE_REMOVE_SPACE:
+ return RemoveSpaceGesture.CREATOR.createFromParcel(parcel);
+ default:
+ throw new UnsupportedOperationException("Unknown type=" + gestureType);
+ }
+ }
+
+ public static final Creator<ParcelableHandwritingGesture> CREATOR = new Parcelable.Creator<>() {
+ @Override
+ public ParcelableHandwritingGesture createFromParcel(Parcel in) {
+ final int gestureType = in.readInt();
+ return new ParcelableHandwritingGesture(createFromParcelInternal(gestureType, in));
+ }
+
+ @Override
+ public ParcelableHandwritingGesture[] newArray(int size) {
+ return new ParcelableHandwritingGesture[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return mGestureAsParcelable.describeContents();
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeInt(mGesture.getGestureType());
+ mGestureAsParcelable.writeToParcel(dest, flags);
+ }
+}
diff --git a/core/java/android/view/inputmethod/RemoteInputConnectionImpl.java b/core/java/android/view/inputmethod/RemoteInputConnectionImpl.java
index f2b7099..ead7924 100644
--- a/core/java/android/view/inputmethod/RemoteInputConnectionImpl.java
+++ b/core/java/android/view/inputmethod/RemoteInputConnectionImpl.java
@@ -28,6 +28,7 @@
import android.annotation.AnyThread;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.graphics.RectF;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
@@ -982,62 +983,9 @@
@Dispatching(cancellable = true)
@Override
- public void performHandwritingSelectGesture(
- InputConnectionCommandHeader header, SelectGesture gesture,
+ public void performHandwritingGesture(
+ InputConnectionCommandHeader header, ParcelableHandwritingGesture gestureContainer,
ResultReceiver resultReceiver) {
- performHandwritingGestureInternal(header, gesture, resultReceiver);
- }
-
- @Dispatching(cancellable = true)
- @Override
- public void performHandwritingSelectRangeGesture(
- InputConnectionCommandHeader header, SelectRangeGesture gesture,
- ResultReceiver resultReceiver) {
- performHandwritingGestureInternal(header, gesture, resultReceiver);
- }
-
- @Dispatching(cancellable = true)
- @Override
- public void performHandwritingInsertGesture(
- InputConnectionCommandHeader header, InsertGesture gesture,
- ResultReceiver resultReceiver) {
- performHandwritingGestureInternal(header, gesture, resultReceiver);
- }
-
- @Dispatching(cancellable = true)
- @Override
- public void performHandwritingDeleteGesture(
- InputConnectionCommandHeader header, DeleteGesture gesture,
- ResultReceiver resultReceiver) {
- performHandwritingGestureInternal(header, gesture, resultReceiver);
- }
-
- @Dispatching(cancellable = true)
- @Override
- public void performHandwritingDeleteRangeGesture(
- InputConnectionCommandHeader header, DeleteRangeGesture gesture,
- ResultReceiver resultReceiver) {
- performHandwritingGestureInternal(header, gesture, resultReceiver);
- }
-
- @Dispatching(cancellable = true)
- @Override
- public void performHandwritingRemoveSpaceGesture(
- InputConnectionCommandHeader header, RemoveSpaceGesture gesture,
- ResultReceiver resultReceiver) {
- performHandwritingGestureInternal(header, gesture, resultReceiver);
- }
-
- @Dispatching(cancellable = true)
- @Override
- public void performHandwritingJoinOrSplitGesture(
- InputConnectionCommandHeader header, JoinOrSplitGesture gesture,
- ResultReceiver resultReceiver) {
- performHandwritingGestureInternal(header, gesture, resultReceiver);
- }
-
- private <T extends HandwritingGesture> void performHandwritingGestureInternal(
- InputConnectionCommandHeader header, T gesture, ResultReceiver resultReceiver) {
dispatchWithTracing("performHandwritingGesture", () -> {
if (header.mSessionId != mCurrentSessionId.get()) {
if (resultReceiver != null) {
@@ -1059,7 +1007,7 @@
// TODO(210039666): implement Cleaner to return HANDWRITING_GESTURE_RESULT_UNKNOWN if
// editor doesn't return any type.
ic.performHandwritingGesture(
- gesture,
+ gestureContainer.get(),
resultReceiver != null ? Runnable::run : null,
resultReceiver != null
? (resultCode) -> resultReceiver.send(resultCode, null /* resultData */)
@@ -1147,6 +1095,36 @@
@Dispatching(cancellable = true)
@Override
+ public void requestTextBoundsInfo(
+ InputConnectionCommandHeader header, RectF rectF,
+ @NonNull ResultReceiver resultReceiver) {
+ dispatchWithTracing("requestTextBoundsInfo", () -> {
+ if (header.mSessionId != mCurrentSessionId.get()) {
+ resultReceiver.send(TextBoundsInfoResult.CODE_CANCELLED, null);
+ return; // cancelled
+ }
+ InputConnection ic = getInputConnection();
+ if (ic == null || !isActive()) {
+ Log.w(TAG, "requestTextBoundsInfo on inactive InputConnection");
+ resultReceiver.send(TextBoundsInfoResult.CODE_CANCELLED, null);
+ return;
+ }
+
+ ic.requestTextBoundsInfo(
+ rectF,
+ Runnable::run,
+ (textBoundsInfoResult) -> {
+ final int resultCode = textBoundsInfoResult.getResultCode();
+ final TextBoundsInfo textBoundsInfo =
+ textBoundsInfoResult.getTextBoundsInfo();
+ resultReceiver.send(resultCode,
+ textBoundsInfo == null ? null : textBoundsInfo.toBundle());
+ });
+ });
+ }
+
+ @Dispatching(cancellable = true)
+ @Override
public void commitContent(InputConnectionCommandHeader header,
InputContentInfo inputContentInfo, int flags, Bundle opts,
AndroidFuture future /* T=Boolean */) {
diff --git a/core/java/android/view/inputmethod/TextBoundsInfo.java b/core/java/android/view/inputmethod/TextBoundsInfo.java
new file mode 100644
index 0000000..4e87405
--- /dev/null
+++ b/core/java/android/view/inputmethod/TextBoundsInfo.java
@@ -0,0 +1,844 @@
+/*
+ * 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.view.inputmethod;
+
+import android.annotation.IntDef;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.graphics.Matrix;
+import android.graphics.RectF;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.text.SegmentFinder;
+
+import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.GrowingArrayUtils;
+import com.android.internal.util.Preconditions;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Arrays;
+import java.util.Objects;
+import java.util.concurrent.Executor;
+import java.util.function.Consumer;
+
+/**
+ * The text bounds information of a slice of text in the editor.
+ *
+ * <p> This class provides IME the layout information of the text within the range from
+ * {@link #getStart()} to {@link #getEnd()}. It's intended to be used by IME as a supplementary API
+ * to support handwriting gestures.
+ * </p>
+ */
+public final class TextBoundsInfo implements Parcelable {
+ /**
+ * The flag indicating that the character is a whitespace.
+ *
+ * @see Builder#setCharacterFlags(int[])
+ * @see #getCharacterFlags(int)
+ */
+ public static final int FLAG_CHARACTER_WHITESPACE = 1;
+
+ /**
+ * The flag indicating that the character is a linefeed character.
+ *
+ * @see Builder#setCharacterFlags(int[])
+ * @see #getCharacterFlags(int)
+ */
+ public static final int FLAG_CHARACTER_LINEFEED = 1 << 1;
+
+ /**
+ * The flag indicating that the character is a punctuation.
+ *
+ * @see Builder#setCharacterFlags(int[])
+ * @see #getCharacterFlags(int)
+ */
+ public static final int FLAG_CHARACTER_PUNCTUATION = 1 << 2;
+
+ /**
+ * The flag indicating that the line this character belongs to has RTL line direction. It's
+ * required that all characters in the same line must have the same direction.
+ *
+ * @see Builder#setCharacterFlags(int[])
+ * @see #getCharacterFlags(int)
+ */
+ public static final int FLAG_LINE_IS_RTL = 1 << 3;
+
+
+ /** @hide */
+ @IntDef(prefix = "FLAG_", flag = true, value = {
+ FLAG_CHARACTER_WHITESPACE,
+ FLAG_CHARACTER_LINEFEED,
+ FLAG_CHARACTER_PUNCTUATION,
+ FLAG_LINE_IS_RTL
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface CharacterFlags {}
+
+ /** All the valid flags. */
+ private static final int KNOWN_CHARACTER_FLAGS = FLAG_CHARACTER_WHITESPACE
+ | FLAG_CHARACTER_LINEFEED | FLAG_CHARACTER_PUNCTUATION | FLAG_LINE_IS_RTL;
+
+ /**
+ * The amount of shift to get the character's BiDi level from the internal character flags.
+ */
+ private static final int BIDI_LEVEL_SHIFT = 19;
+
+ /**
+ * The mask used to get the character's BiDi level from the internal character flags.
+ */
+ private static final int BIDI_LEVEL_MASK = 0x7F << BIDI_LEVEL_SHIFT;
+
+ /**
+ * The flag indicating that the character at the index is the start of a line segment.
+ * This flag is only used internally to serialize the {@link SegmentFinder}.
+ *
+ * @see #writeToParcel(Parcel, int)
+ */
+ private static final int FLAG_LINE_SEGMENT_START = 1 << 31;
+
+ /**
+ * The flag indicating that the character at the index is the end of a line segment.
+ * This flag is only used internally to serialize the {@link SegmentFinder}.
+ *
+ * @see #writeToParcel(Parcel, int)
+ */
+ private static final int FLAG_LINE_SEGMENT_END = 1 << 30;
+
+ /**
+ * The flag indicating that the character at the index is the start of a word segment.
+ * This flag is only used internally to serialize the {@link SegmentFinder}.
+ *
+ * @see #writeToParcel(Parcel, int)
+ */
+ private static final int FLAG_WORD_SEGMENT_START = 1 << 29;
+
+ /**
+ * The flag indicating that the character at the index is the end of a word segment.
+ * This flag is only used internally to serialize the {@link SegmentFinder}.
+ *
+ * @see #writeToParcel(Parcel, int)
+ */
+ private static final int FLAG_WORD_SEGMENT_END = 1 << 28;
+
+ /**
+ * The flag indicating that the character at the index is the start of a grapheme segment.
+ * It's only used internally to serialize the {@link SegmentFinder}.
+ *
+ * @see #writeToParcel(Parcel, int)
+ */
+ private static final int FLAG_GRAPHEME_SEGMENT_START = 1 << 27;
+
+ /**
+ * The flag indicating that the character at the index is the end of a grapheme segment.
+ * It's only used internally to serialize the {@link SegmentFinder}.
+ *
+ * @see #writeToParcel(Parcel, int)
+ */
+ private static final int FLAG_GRAPHEME_SEGMENT_END = 1 << 26;
+
+ private final int mStart;
+ private final int mEnd;
+ private final float[] mMatrixValues;
+ private final float[] mCharacterBounds;
+ /**
+ * The array that encodes character and BiDi levels. They are stored together to save memory
+ * space, and it's easier during serialization.
+ */
+ private final int[] mInternalCharacterFlags;
+ private final SegmentFinder mLineSegmentFinder;
+ private final SegmentFinder mWordSegmentFinder;
+ private final SegmentFinder mGraphemeSegmentFinder;
+
+ /**
+ * Returns a new instance of {@link android.graphics.Matrix} that indicates the transformation
+ * matrix that is to be applied other positional data in this class.
+ *
+ * @return a new instance (copy) of the transformation matrix.
+ */
+ @NonNull
+ public Matrix getMatrix() {
+ final Matrix matrix = new Matrix();
+ matrix.setValues(mMatrixValues);
+ return matrix;
+ }
+
+ /**
+ * Returns the index of the first character whose bounds information is available in this
+ * {@link TextBoundsInfo}, inclusive.
+ *
+ * @see Builder#setStartAndEnd(int, int)
+ */
+ public int getStart() {
+ return mStart;
+ }
+
+ /**
+ * Returns the index of the last character whose bounds information is available in this
+ * {@link TextBoundsInfo}, exclusive.
+ *
+ * @see Builder#setStartAndEnd(int, int)
+ */
+ public int getEnd() {
+ return mEnd;
+ }
+
+ /**
+ * Return the bounds of the character at the given {@code index}, in the coordinates of the
+ * editor.
+ *
+ * @param index the index of the queried character.
+ * @return the bounding box of the queried character.
+ *
+ * @throws IndexOutOfBoundsException if the given {@code index} is out of the range from
+ * the {@code start} to the {@code end}.
+ */
+ @NonNull
+ public RectF getCharacterBounds(int index) {
+ if (index < mStart || index >= mEnd) {
+ throw new IndexOutOfBoundsException("Index is out of the bounds of "
+ + "[" + mStart + ", " + mEnd + ").");
+ }
+ final int offset = 4 * (index - mStart);
+ return new RectF(mCharacterBounds[offset], mCharacterBounds[offset + 1],
+ mCharacterBounds[offset + 2], mCharacterBounds[offset + 3]);
+ }
+
+ /**
+ * Return the flags associated with the character at the given {@code index}.
+ * The flags contain the following information:
+ * <ul>
+ * <li>The {@link #FLAG_CHARACTER_WHITESPACE} flag, indicating the character is a
+ * whitespace. </li>
+ * <li>The {@link #FLAG_CHARACTER_LINEFEED} flag, indicating the character is a
+ * linefeed. </li>
+ * <li>The {@link #FLAG_CHARACTER_PUNCTUATION} flag, indicating the character is a
+ * punctuation. </li>
+ * <li>The {@link #FLAG_LINE_IS_RTL} flag, indicating the line this character belongs to
+ * has RTL line direction. All characters in the same line must have the same line
+ * direction. Check {@link #getLineSegmentFinder()} for more information of
+ * line boundaries. </li>
+ * </ul>
+ *
+ * @param index the index of the queried character.
+ * @return the flags associated with the queried character.
+ *
+ * @throws IndexOutOfBoundsException if the given {@code index} is out of the range from
+ * the {@code start} to the {@code end}.
+ *
+ * @see #FLAG_CHARACTER_WHITESPACE
+ * @see #FLAG_CHARACTER_LINEFEED
+ * @see #FLAG_CHARACTER_PUNCTUATION
+ * @see #FLAG_LINE_IS_RTL
+ */
+ @CharacterFlags
+ public int getCharacterFlags(int index) {
+ if (index < mStart || index >= mEnd) {
+ throw new IndexOutOfBoundsException("Index is out of the bounds of "
+ + "[" + mStart + ", " + mEnd + ").");
+ }
+ final int offset = index - mStart;
+ return mInternalCharacterFlags[offset] & KNOWN_CHARACTER_FLAGS;
+ }
+
+ /**
+ * The BiDi level of the character at the given {@code index}. <br/>
+ * BiDi level is defined by
+ * <a href="https://unicode.org/reports/tr9/#Basic_Display_Algorithm" >the unicode
+ * bidirectional algorithm </a>. One can determine whether a character's direction is
+ * right-to-left (RTL) or left-to-right (LTR) by checking the last bit of the BiDi level.
+ * If it's 1, the character is RTL, otherwise the character is LTR. The BiDi level of a
+ * character must be in the range of [0, 125].
+ *
+ * @param index the index of the queried character.
+ * @return the BiDi level of the character, which is an integer in the range of [0, 125].
+ * @throws IndexOutOfBoundsException if the given {@code index} is out of the range from
+ * the {@code start} to the {@code end}.
+ *
+ * @see Builder#setCharacterBidiLevel(int[])
+ */
+ @IntRange(from = 0, to = 125)
+ public int getCharacterBidiLevel(int index) {
+ if (index < mStart || index >= mEnd) {
+ throw new IndexOutOfBoundsException("Index is out of the bounds of "
+ + "[" + mStart + ", " + mEnd + ").");
+ }
+ final int offset = index - mStart;
+ return (mInternalCharacterFlags[offset] & BIDI_LEVEL_MASK) >> BIDI_LEVEL_SHIFT;
+ }
+
+ /**
+ * Returns the {@link SegmentFinder} that locates the word boundaries.
+ *
+ * @see Builder#setWordSegmentFinder(SegmentFinder)
+ */
+ @NonNull
+ public SegmentFinder getWordSegmentFinder() {
+ return mWordSegmentFinder;
+ }
+
+ /**
+ * Returns the {@link SegmentFinder} that locates the grapheme boundaries.
+ *
+ * @see Builder#setGraphemeSegmentFinder(SegmentFinder)
+ */
+ @NonNull
+ public SegmentFinder getGraphemeSegmentFinder() {
+ return mGraphemeSegmentFinder;
+ }
+
+ /**
+ * Returns the {@link SegmentFinder} that locates the line boundaries.
+ *
+ * @see Builder#setLineSegmentFinder(SegmentFinder)
+ */
+ @NonNull
+ public SegmentFinder getLineSegmentFinder() {
+ return mLineSegmentFinder;
+ }
+
+ /**
+ * Describe the kinds of special objects contained in this Parcelable
+ * instance's marshaled representation. For example, if the object will
+ * include a file descriptor in the output of {@link #writeToParcel(Parcel, int)},
+ * the return value of this method must include the
+ * {@link #CONTENTS_FILE_DESCRIPTOR} bit.
+ *
+ * @return a bitmask indicating the set of special object types marshaled
+ * by this Parcelable object instance.
+ */
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /**
+ * Flatten this object in to a Parcel.
+ *
+ * @param dest The Parcel in which the object should be written.
+ * @param flags Additional flags about how the object should be written.
+ * May be 0 or {@link #PARCELABLE_WRITE_RETURN_VALUE}.
+ */
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeInt(mStart);
+ dest.writeInt(mEnd);
+ dest.writeFloatArray(mMatrixValues);
+ dest.writeFloatArray(mCharacterBounds);
+
+ // The end can also be a break position. We need an extra space to encode the breaks.
+ final int[] encodedFlags = Arrays.copyOf(mInternalCharacterFlags, mEnd - mStart + 1);
+ encodeSegmentFinder(encodedFlags, FLAG_GRAPHEME_SEGMENT_START, FLAG_GRAPHEME_SEGMENT_END,
+ mStart, mEnd, mGraphemeSegmentFinder);
+ encodeSegmentFinder(encodedFlags, FLAG_WORD_SEGMENT_START, FLAG_WORD_SEGMENT_END, mStart,
+ mEnd, mWordSegmentFinder);
+ encodeSegmentFinder(encodedFlags, FLAG_LINE_SEGMENT_START, FLAG_LINE_SEGMENT_END, mStart,
+ mEnd, mLineSegmentFinder);
+ dest.writeIntArray(encodedFlags);
+ }
+
+ private TextBoundsInfo(Parcel source) {
+ mStart = source.readInt();
+ mEnd = source.readInt();
+ mMatrixValues = Objects.requireNonNull(source.createFloatArray());
+ mCharacterBounds = Objects.requireNonNull(source.createFloatArray());
+ final int[] encodedFlags = Objects.requireNonNull(source.createIntArray());
+
+ mGraphemeSegmentFinder = decodeSegmentFinder(encodedFlags, FLAG_GRAPHEME_SEGMENT_START,
+ FLAG_GRAPHEME_SEGMENT_END, mStart, mEnd);
+ mWordSegmentFinder = decodeSegmentFinder(encodedFlags, FLAG_WORD_SEGMENT_START,
+ FLAG_WORD_SEGMENT_END, mStart, mEnd);
+ mLineSegmentFinder = decodeSegmentFinder(encodedFlags, FLAG_LINE_SEGMENT_START,
+ FLAG_LINE_SEGMENT_END, mStart, mEnd);
+
+ final int length = mEnd - mStart;
+ final int flagsMask = KNOWN_CHARACTER_FLAGS | BIDI_LEVEL_MASK;
+ mInternalCharacterFlags = new int[length];
+ for (int i = 0; i < length; ++i) {
+ // Remove the flags used to encoded segment boundaries.
+ mInternalCharacterFlags[i] = encodedFlags[i] & flagsMask;
+ }
+ }
+
+ private TextBoundsInfo(Builder builder) {
+ mStart = builder.mStart;
+ mEnd = builder.mEnd;
+ mMatrixValues = Arrays.copyOf(builder.mMatrixValues, 9);
+ final int length = mEnd - mStart;
+ mCharacterBounds = Arrays.copyOf(builder.mCharacterBounds, 4 * length);
+ // Store characterFlags and characterBidiLevels to save memory.
+ mInternalCharacterFlags = new int[length];
+ for (int index = 0; index < length; ++index) {
+ mInternalCharacterFlags[index] = builder.mCharacterFlags[index]
+ | (builder.mCharacterBidiLevels[index] << BIDI_LEVEL_SHIFT);
+ }
+ mGraphemeSegmentFinder = builder.mGraphemeSegmentFinder;
+ mWordSegmentFinder = builder.mWordSegmentFinder;
+ mLineSegmentFinder = builder.mLineSegmentFinder;
+ }
+
+ /**
+ * The CREATOR to make this class Parcelable.
+ */
+ @NonNull
+ public static final Parcelable.Creator<TextBoundsInfo> CREATOR = new Creator<TextBoundsInfo>() {
+ @Override
+ public TextBoundsInfo createFromParcel(Parcel source) {
+ return new TextBoundsInfo(source);
+ }
+
+ @Override
+ public TextBoundsInfo[] newArray(int size) {
+ return new TextBoundsInfo[size];
+ }
+ };
+
+ private static final String TEXT_BOUNDS_INFO_KEY = "android.view.inputmethod.TextBoundsInfo";
+
+ /**
+ * Store the {@link TextBoundsInfo} into a {@link Bundle}. This method is used by
+ * {@link RemoteInputConnectionImpl} to transfer the {@link TextBoundsInfo} from the editor
+ * to IME.
+ *
+ * @see TextBoundsInfoResult
+ * @see InputConnection#requestTextBoundsInfo(RectF, Executor, Consumer)
+ * @hide
+ */
+ @NonNull
+ public Bundle toBundle() {
+ final Bundle bundle = new Bundle();
+ bundle.putParcelable(TEXT_BOUNDS_INFO_KEY, this);
+ return bundle;
+
+ }
+
+ /** @hide */
+ @Nullable
+ public static TextBoundsInfo createFromBundle(@Nullable Bundle bundle) {
+ if (bundle == null) return null;
+ return bundle.getParcelable(TEXT_BOUNDS_INFO_KEY, TextBoundsInfo.class);
+ }
+
+ /**
+ * The builder class to create a {@link TextBoundsInfo} object.
+ */
+ public static final class Builder {
+ private final float[] mMatrixValues = new float[9];
+ private boolean mMatrixInitialized;
+ private int mStart;
+ private int mEnd;
+ private float[] mCharacterBounds;
+ private int[] mCharacterFlags;
+ private int[] mCharacterBidiLevels;
+ private SegmentFinder mLineSegmentFinder;
+ private SegmentFinder mWordSegmentFinder;
+ private SegmentFinder mGraphemeSegmentFinder;
+
+ /** Clear all the parameters set on this {@link Builder} to reuse it. */
+ @NonNull
+ public Builder clear() {
+ mMatrixInitialized = false;
+ mStart = -1;
+ mEnd = -1;
+ mCharacterBounds = null;
+ mCharacterFlags = null;
+ mLineSegmentFinder = null;
+ mWordSegmentFinder = null;
+ mGraphemeSegmentFinder = null;
+ return this;
+ }
+
+ /**
+ * Sets the matrix that transforms local coordinates into screen coordinates.
+ *
+ * @param matrix transformation matrix from local coordinates into screen coordinates.
+ * @throws NullPointerException if the given {@code matrix} is {@code null}.
+ */
+ @NonNull
+ public Builder setMatrix(@NonNull Matrix matrix) {
+ Objects.requireNonNull(matrix).getValues(mMatrixValues);
+ mMatrixInitialized = true;
+ return this;
+ }
+
+ /**
+ * Set the start and end index of the {@link TextBoundsInfo}. It's the range of the
+ * characters whose information is available in the {@link TextBoundsInfo}.
+ *
+ * @param start the start index of the {@link TextBoundsInfo}, inclusive.
+ * @param end the end index of the {@link TextBoundsInfo}, exclusive.
+ * @throws IllegalArgumentException if the given {@code start} or {@code end} is negative,
+ * or {@code end} is smaller than the {@code start}.
+ */
+ @NonNull
+ @SuppressWarnings("MissingGetterMatchingBuilder")
+ public Builder setStartAndEnd(@IntRange(from = 0) int start, @IntRange(from = 0) int end) {
+ Preconditions.checkArgument(start >= 0);
+ Preconditions.checkArgumentInRange(start, 0, end, "start");
+ mStart = start;
+ mEnd = end;
+ return this;
+ }
+
+ /**
+ * Set the characters bounds, in the coordinates of the editor. <br/>
+ *
+ * The given array should be divided into groups of four where each element represents
+ * left, top, right and bottom of the character bounds respectively.
+ * The bounds of the i-th character in the editor should be stored at index
+ * 4 * (i - start). The length of the given array must equal to 4 * (end - start). <br/>
+ *
+ * Sometimes multiple characters in a single grapheme are rendered as one symbol on the
+ * screen. So those characters only have one shared bounds. In this case, we recommend the
+ * editor to assign all the width to the bounds of the first character in the grapheme,
+ * and make the rest characters' bounds zero-width. <br/>
+ *
+ * For example, the string "'0xD83D' '0xDE00'" is rendered as one grapheme - a grinning face
+ * emoji. If the bounds of the grapheme is: Rect(5, 10, 15, 20), the character bounds of the
+ * string should be: [ Rect(5, 10, 15, 20), Rect(15, 10, 15, 20) ].
+ *
+ * @param characterBounds the array of the flattened character bounds.
+ * @throws NullPointerException if the given {@code characterBounds} is {@code null}.
+ */
+ @NonNull
+ public Builder setCharacterBounds(@NonNull float[] characterBounds) {
+ mCharacterBounds = Objects.requireNonNull(characterBounds);
+ return this;
+ }
+
+ /**
+ * Set the flags of the characters. The flags of the i-th character in the editor is stored
+ * at index (i - start). The length of the given array must equal to (end - start).
+ * The flags contain the following information:
+ * <ul>
+ * <li>The {@link #FLAG_CHARACTER_WHITESPACE} flag, indicating the character is a
+ * whitespace. </li>
+ * <li>The {@link #FLAG_CHARACTER_LINEFEED} flag, indicating the character is a
+ * linefeed. </li>
+ * <li>The {@link #FLAG_CHARACTER_PUNCTUATION} flag, indicating the character is a
+ * punctuation. </li>
+ * <li>The {@link #FLAG_LINE_IS_RTL} flag, indicating the line this character belongs to
+ * is RTL. All all character in the same line must have the same line direction. Check
+ * {@link #getLineSegmentFinder()} for more information of line boundaries. </li>
+ * </ul>
+ *
+ * @param characterFlags the array of the character's flags.
+ * @throws NullPointerException if the given {@code characterFlags} is {@code null}.
+ * @throws IllegalArgumentException if the given {@code characterFlags} contains invalid
+ * flags.
+ *
+ * @see #getCharacterFlags(int)
+ */
+ @NonNull
+ public Builder setCharacterFlags(@NonNull int[] characterFlags) {
+ Objects.requireNonNull(characterFlags);
+ for (int characterFlag : characterFlags) {
+ if ((characterFlag & (~KNOWN_CHARACTER_FLAGS)) != 0) {
+ throw new IllegalArgumentException("characterFlags contains invalid flags.");
+ }
+ }
+ mCharacterFlags = characterFlags;
+ return this;
+ }
+
+ /**
+ * Set the BiDi levels for the character. The bidiLevel of the i-th character in the editor
+ * is stored at index (i - start). The length of the given array must equal to
+ * (end - start). <br/>
+ *
+ * BiDi level is defined by
+ * <a href="https://unicode.org/reports/tr9/#Basic_Display_Algorithm" >the unicode
+ * bidirectional algorithm </a>. One can determine whether a character's direction is
+ * right-to-left (RTL) or left-to-right (LTR) by checking the last bit of the BiDi level.
+ * If it's 1, the character is RTL, otherwise the character is LTR. The BiDi level of a
+ * character must be in the range of [0, 125].
+ * @param characterBidiLevels the array of the character's BiDi level.
+ *
+ * @throws NullPointerException if the given {@code characterBidiLevels} is {@code null}.
+ * @throws IllegalArgumentException if the given {@code characterBidiLevels} contains an
+ * element that's out of the range [0, 125].
+ *
+ * @see #getCharacterBidiLevel(int)
+ */
+ @NonNull
+ public Builder setCharacterBidiLevel(@NonNull int[] characterBidiLevels) {
+ Objects.requireNonNull(characterBidiLevels);
+ for (int index = 0; index < characterBidiLevels.length; ++index) {
+ Preconditions.checkArgumentInRange(characterBidiLevels[index], 0, 125,
+ "bidiLevels[" + index + "]");
+ }
+ mCharacterBidiLevels = characterBidiLevels;
+ return this;
+ }
+
+ /**
+ * Set the {@link SegmentFinder} that locates the grapheme cluster boundaries. Grapheme is
+ * defined in <a href="https://unicode.org/reports/tr29/#Grapheme_Cluster_Boundaries">
+ * the unicode annex #29: unicode text segmentation<a/>. It's a user-perspective character.
+ * And it's usually the minimal unit for selection, backspace, deletion etc. <br/>
+ *
+ * Please note that only the grapheme segments within the range from start to end will
+ * be available to the IME. The remaining information will be discarded during serialization
+ * for better performance.
+ *
+ * @param graphemeSegmentFinder the {@link SegmentFinder} that locates the grapheme cluster
+ * boundaries.
+ * @throws NullPointerException if the given {@code graphemeSegmentFinder} is {@code null}.
+ *
+ * @see #getGraphemeSegmentFinder()
+ * @see SegmentFinder
+ * @see SegmentFinder.DefaultSegmentFinder
+ */
+ @NonNull
+ public Builder setGraphemeSegmentFinder(@NonNull SegmentFinder graphemeSegmentFinder) {
+ mGraphemeSegmentFinder = Objects.requireNonNull(graphemeSegmentFinder);
+ return this;
+ }
+
+ /**
+ * Set the {@link SegmentFinder} that locates the word boundaries. <br/>
+ *
+ * Please note that only the word segments within the range from start to end will
+ * be available to the IME. The remaining information will be discarded during serialization
+ * for better performance.
+ * @param wordSegmentFinder set the {@link SegmentFinder} that locates the word boundaries.
+ * @throws NullPointerException if the given {@code wordSegmentFinder} is {@code null}.
+ *
+ * @see #getWordSegmentFinder()
+ * @see SegmentFinder
+ * @see SegmentFinder.DefaultSegmentFinder
+ */
+ @NonNull
+ public Builder setWordSegmentFinder(@NonNull SegmentFinder wordSegmentFinder) {
+ mWordSegmentFinder = Objects.requireNonNull(wordSegmentFinder);
+ return this;
+ }
+
+ /**
+ * Set the {@link SegmentFinder} that locates the line boundaries. Aside from the hard
+ * breaks in the text, it should also locate the soft line breaks added by the editor.
+ * It is expected that the characters within the same line is rendered on the same baseline.
+ * (Except for some text formatted as subscript and superscript.) <br/>
+ *
+ * Please note that only the line segments within the range from start to end will
+ * be available to the IME. The remaining information will be discarded during serialization
+ * for better performance.
+ * @param lineSegmentFinder set the {@link SegmentFinder} that locates the line boundaries.
+ * @throws NullPointerException if the given {@code lineSegmentFinder} is {@code null}.
+ *
+ * @see #getLineSegmentFinder()
+ * @see SegmentFinder
+ * @see SegmentFinder.DefaultSegmentFinder
+ */
+ @NonNull
+ public Builder setLineSegmentFinder(@NonNull SegmentFinder lineSegmentFinder) {
+ mLineSegmentFinder = Objects.requireNonNull(lineSegmentFinder);
+ return this;
+ }
+
+ /**
+ * Create the {@link TextBoundsInfo} using the parameters in this {@link Builder}.
+ *
+ * @throws IllegalStateException in the following conditions:
+ * <ul>
+ * <li>if the {@code start} or {@code end} is not set.</li>
+ * <li>if the {@code matrix} is not set.</li>
+ * <li>if {@code characterBounds} is not set or its length doesn't equal to
+ * 4 * ({@code end} - {@code start}).</li>
+ * <li>if the {@code characterFlags} is not set or its length doesn't equal to
+ * ({@code end} - {@code start}).</li>
+ * <li>if {@code graphemeSegmentFinder}, {@code wordSegmentFinder} or
+ * {@code lineSegmentFinder} is not set.</li>
+ * <li>if characters in the same line has inconsistent {@link #FLAG_LINE_IS_RTL}
+ * flag.</li>
+ * </ul>
+ */
+ @NonNull
+ public TextBoundsInfo build() {
+ if (mStart < 0 || mEnd < 0) {
+ throw new IllegalStateException("Start and end must be set.");
+ }
+
+ if (!mMatrixInitialized) {
+ throw new IllegalStateException("Matrix must be set.");
+ }
+
+ if (mCharacterBounds == null) {
+ throw new IllegalStateException("CharacterBounds must be set.");
+ }
+
+ if (mCharacterFlags == null) {
+ throw new IllegalStateException("CharacterFlags must be set.");
+ }
+
+ if (mCharacterBidiLevels == null) {
+ throw new IllegalStateException("CharacterBidiLevel must be set.");
+ }
+
+ if (mCharacterBounds.length != 4 * (mEnd - mStart)) {
+ throw new IllegalStateException("The length of characterBounds doesn't match the "
+ + "length of the given start and end."
+ + " Expected length: " + (4 * (mEnd - mStart))
+ + " characterBounds length: " + mCharacterBounds.length);
+ }
+ if (mCharacterFlags.length != mEnd - mStart) {
+ throw new IllegalStateException("The length of characterFlags doesn't match the "
+ + "length of the given start and end."
+ + " Expected length: " + (mEnd - mStart)
+ + " characterFlags length: " + mCharacterFlags.length);
+ }
+ if (mCharacterBidiLevels.length != mEnd - mStart) {
+ throw new IllegalStateException("The length of characterBidiLevels doesn't match"
+ + " the length of the given start and end."
+ + " Expected length: " + (mEnd - mStart)
+ + " characterFlags length: " + mCharacterBidiLevels.length);
+ }
+ if (mGraphemeSegmentFinder == null) {
+ throw new IllegalStateException("GraphemeSegmentFinder must be set.");
+ }
+ if (mWordSegmentFinder == null) {
+ throw new IllegalStateException("WordSegmentFinder must be set.");
+ }
+ if (mLineSegmentFinder == null) {
+ throw new IllegalStateException("LineSegmentFinder must be set.");
+ }
+
+ if (!isLineDirectionFlagConsistent(mCharacterFlags, mLineSegmentFinder, mStart, mEnd)) {
+ throw new IllegalStateException("characters in the same line must have the same "
+ + "FLAG_LINE_IS_RTL flag value.");
+ }
+ return new TextBoundsInfo(this);
+ }
+ }
+
+ /**
+ * Encode the segment start and end positions in {@link SegmentFinder} to a flags array.
+ *
+ * For example:
+ * Text: "A BC DE"
+ * Input:
+ * start: 2, end: 7 // substring "BC DE"
+ * SegmentFinder: segment ranges = [(2, 4), (5, 7)] // a word break iterator
+ * flags: [0x0000, 0x0000, 0x0080, 0x0000, 0x0000, 0x0000] // 0x0080 is whitespace
+ * segmentStartFlag: 0x0100
+ * segmentEndFlag: 0x0200
+ * Output:
+ * flags: [0x0100, 0x0000, 0x0280, 0x0100, 0x0000, 0x0200]
+ * The index 2 and 5 encode segment starts, the index 4 and 7 encode a segment end.
+ *
+ * @param flags the flags array to receive the results.
+ * @param segmentStartFlag the flag used to encode the segment start.
+ * @param segmentEndFlag the flag used to encode the segment end.
+ * @param start the start index of the encoded range, inclusive.
+ * @param end the end index of the encoded range, inclusive.
+ * @param segmentFinder the SegmentFinder to be encoded.
+ *
+ * @see #decodeSegmentFinder(int[], int, int, int, int)
+ */
+ private static void encodeSegmentFinder(@NonNull int[] flags, int segmentStartFlag,
+ int segmentEndFlag, int start, int end, @NonNull SegmentFinder segmentFinder) {
+ if (end - start + 1 != flags.length) {
+ throw new IllegalStateException("The given flags array must have the same length as"
+ + " the given range. flags length: " + flags.length
+ + " range: [" + start + ", " + end + "]");
+ }
+
+ int segmentEnd = segmentFinder.nextEndBoundary(start);
+ if (segmentEnd == SegmentFinder.DONE) return;
+ int segmentStart = segmentFinder.previousStartBoundary(segmentEnd);
+
+ while (segmentEnd != SegmentFinder.DONE && segmentEnd <= end) {
+ if (segmentStart >= start) {
+ flags[segmentStart - start] |= segmentStartFlag;
+ flags[segmentEnd - start] |= segmentEndFlag;
+ }
+ segmentStart = segmentFinder.nextStartBoundary(segmentStart);
+ segmentEnd = segmentFinder.nextEndBoundary(segmentEnd);
+ }
+ }
+
+ /**
+ * Decode a {@link SegmentFinder} from a flags array.
+ *
+ * For example:
+ * Text: "A BC DE"
+ * Input:
+ * start: 2, end: 7 // substring "BC DE"
+ * flags: [0x0100, 0x0000, 0x0280, 0x0100, 0x0000, 0x0200]
+ * segmentStartFlag: 0x0100
+ * segmentEndFlag: 0x0200
+ * Output:
+ * SegmentFinder: segment ranges = [(2, 4), (5, 7)]
+ *
+ * @param flags the flags array to decode the SegmentFinder.
+ * @param segmentStartFlag the flag to decode a segment start.
+ * @param segmentEndFlag the flag to decode a segment end.
+ * @param start the start index of the interested range, inclusive.
+ * @param end the end index of the interested range, inclusive.
+ *
+ * @see #encodeSegmentFinder(int[], int, int, int, int, SegmentFinder)
+ */
+ private static SegmentFinder decodeSegmentFinder(int[] flags, int segmentStartFlag,
+ int segmentEndFlag, int start, int end) {
+ if (end - start + 1 != flags.length) {
+ throw new IllegalStateException("The given flags array must have the same length as"
+ + " the given range. flags length: " + flags.length
+ + " range: [" + start + ", " + end + "]");
+ }
+ int[] breaks = ArrayUtils.newUnpaddedIntArray(10);
+ int count = 0;
+ for (int offset = 0; offset < flags.length; ++offset) {
+ if ((flags[offset] & segmentStartFlag) == segmentStartFlag) {
+ breaks = GrowingArrayUtils.append(breaks, count++, start + offset);
+ }
+ if ((flags[offset] & segmentEndFlag) == segmentEndFlag) {
+ breaks = GrowingArrayUtils.append(breaks, count++, start + offset);
+ }
+ }
+ return new SegmentFinder.DefaultSegmentFinder(Arrays.copyOf(breaks, count));
+ }
+
+ /**
+ * Check whether the {@link #FLAG_LINE_IS_RTL} is the same for characters in the same line.
+ * @return true if all characters in the same line has the same {@link #FLAG_LINE_IS_RTL} flag.
+ */
+ private static boolean isLineDirectionFlagConsistent(int[] characterFlags,
+ SegmentFinder lineSegmentFinder, int start, int end) {
+ int segmentEnd = lineSegmentFinder.nextEndBoundary(start);
+ if (segmentEnd == SegmentFinder.DONE) return true;
+ int segmentStart = lineSegmentFinder.previousStartBoundary(segmentEnd);
+
+ while (segmentStart != SegmentFinder.DONE && segmentStart < end) {
+ final int lineStart = Math.max(segmentStart, start);
+ final int lineEnd = Math.min(segmentEnd, end);
+ final boolean lineIsRtl = (characterFlags[lineStart - start] & FLAG_LINE_IS_RTL) != 0;
+ for (int index = lineStart + 1; index < lineEnd; ++index) {
+ final int flags = characterFlags[index - start];
+ final boolean characterLineIsRtl = (flags & FLAG_LINE_IS_RTL) != 0;
+ if (characterLineIsRtl != lineIsRtl) {
+ return false;
+ }
+ }
+
+ segmentStart = lineSegmentFinder.nextStartBoundary(segmentStart);
+ segmentEnd = lineSegmentFinder.nextEndBoundary(segmentEnd);
+ }
+ return true;
+ }
+}
diff --git a/core/java/android/view/inputmethod/TextBoundsInfoResult.java b/core/java/android/view/inputmethod/TextBoundsInfoResult.java
new file mode 100644
index 0000000..62df17a
--- /dev/null
+++ b/core/java/android/view/inputmethod/TextBoundsInfoResult.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.inputmethod;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.graphics.RectF;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.concurrent.Executor;
+import java.util.function.Consumer;
+
+/**
+ * The object that holds the result of the
+ * {@link InputConnection#requestTextBoundsInfo(RectF, Executor, Consumer)} call.
+ *
+ * @see InputConnection#requestTextBoundsInfo(RectF, Executor, Consumer)
+ */
+public final class TextBoundsInfoResult {
+ private final int mResultCode;
+ private final TextBoundsInfo mTextBoundsInfo;
+
+ /**
+ * Result for {@link InputConnection#requestTextBoundsInfo(RectF, Executor, Consumer)} when the
+ * editor doesn't implement the method.
+ */
+ public static final int CODE_UNSUPPORTED = 0;
+
+ /**
+ * Result for {@link InputConnection#requestTextBoundsInfo(RectF, Executor, Consumer)} when the
+ * editor successfully returns a {@link TextBoundsInfo}.
+ */
+ public static final int CODE_SUCCESS = 1;
+
+ /**
+ * Result for {@link InputConnection#requestTextBoundsInfo(RectF, Executor, Consumer)} when the
+ * request failed. This result code is returned when the editor can't provide a valid
+ * {@link TextBoundsInfo}. (e.g. The editor view is not laid out.)
+ */
+ public static final int CODE_FAILED = 2;
+
+ /**
+ * Result for {@link InputConnection#requestTextBoundsInfo(RectF, Executor, Consumer)} when the
+ * request is cancelled. This happens when the {@link InputConnection} is or becomes
+ * invalidated while requesting the
+ * {@link TextBoundsInfo}, for example because a new {@code InputConnection} was started, or
+ * due to {@link InputMethodManager#invalidateInput}.
+ */
+ public static final int CODE_CANCELLED = 3;
+
+ /** @hide */
+ @IntDef(prefix = { "CODE_" }, value = {
+ CODE_UNSUPPORTED,
+ CODE_SUCCESS,
+ CODE_FAILED,
+ CODE_CANCELLED,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ResultCode {}
+
+ /**
+ * Create a {@link TextBoundsInfoResult} object with no {@link TextBoundsInfo}.
+ * The given {@code resultCode} can't be {@link #CODE_SUCCESS}.
+ * @param resultCode the result code of the
+ * {@link InputConnection#requestTextBoundsInfo(RectF, Executor, Consumer)} call.
+ */
+ public TextBoundsInfoResult(@ResultCode int resultCode) {
+ this(resultCode, null);
+ }
+
+ /**
+ * Create a {@link TextBoundsInfoResult} object.
+ *
+ * @param resultCode the result code of the
+ * {@link InputConnection#requestTextBoundsInfo(RectF, Executor, Consumer)} call.
+ * @param textBoundsInfo the returned {@link TextBoundsInfo} of the
+ * {@link InputConnection#requestTextBoundsInfo(RectF, Executor, Consumer)} call. It can't be
+ * null if the {@code resultCode} is {@link #CODE_SUCCESS}.
+ *
+ * @throws IllegalStateException if the resultCode is
+ * {@link #CODE_SUCCESS} but the given {@code textBoundsInfo}
+ * is null.
+ */
+ public TextBoundsInfoResult(@ResultCode int resultCode,
+ @NonNull TextBoundsInfo textBoundsInfo) {
+ if (resultCode == CODE_SUCCESS && textBoundsInfo == null) {
+ throw new IllegalStateException("TextBoundsInfo must be provided when the resultCode "
+ + "is CODE_SUCCESS.");
+ }
+ mResultCode = resultCode;
+ mTextBoundsInfo = textBoundsInfo;
+ }
+
+ /**
+ * Return the result code of the
+ * {@link InputConnection#requestTextBoundsInfo(RectF, Executor, Consumer)} call.
+ * Its value is one of the {@link #CODE_UNSUPPORTED}, {@link #CODE_SUCCESS},
+ * {@link #CODE_FAILED} and {@link #CODE_CANCELLED}.
+ */
+ @ResultCode
+ public int getResultCode() {
+ return mResultCode;
+ }
+
+ /**
+ * Return the {@link TextBoundsInfo} provided by the editor. It is non-null if the
+ * {@code resultCode} is {@link #CODE_SUCCESS}.
+ * Otherwise, it can be null in the following conditions:
+ * <ul>
+ * <li>the editor doesn't support
+ * {@link InputConnection#requestTextBoundsInfo(RectF, Executor, Consumer)}.</li>
+ * <li>the editor doesn't have the text bounds information at the moment. (e.g. the editor
+ * view is not laid out yet.) </li>
+ * <li> the {@link InputConnection} is or become inactive during the request. </li>
+ * <ul/>
+ */
+ @Nullable
+ public TextBoundsInfo getTextBoundsInfo() {
+ return mTextBoundsInfo;
+ }
+}
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index b5c58fb..1144b59 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -69,6 +69,7 @@
import android.graphics.BlendMode;
import android.graphics.Canvas;
import android.graphics.Insets;
+import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Paint.FontMetricsInt;
import android.graphics.Path;
@@ -200,6 +201,7 @@
import android.view.inputmethod.RemoveSpaceGesture;
import android.view.inputmethod.SelectGesture;
import android.view.inputmethod.SelectRangeGesture;
+import android.view.inputmethod.TextBoundsInfo;
import android.view.inspector.InspectableProperty;
import android.view.inspector.InspectableProperty.EnumEntry;
import android.view.inspector.InspectableProperty.FlagEntry;
@@ -12953,18 +12955,15 @@
getLocalVisibleRect(rect);
final RectF visibleRect = new RectF(rect);
- final float[] characterBounds = new float[4 * (endIndex - startIndex)];
- mLayout.fillCharacterBounds(startIndex, endIndex, characterBounds, 0);
+
+ final float[] characterBounds = getCharacterBounds(startIndex, endIndex,
+ viewportToContentHorizontalOffset, viewportToContentVerticalOffset);
final int limit = endIndex - startIndex;
for (int offset = 0; offset < limit; ++offset) {
- final float left =
- characterBounds[offset * 4] + viewportToContentHorizontalOffset;
- final float top =
- characterBounds[offset * 4 + 1] + viewportToContentVerticalOffset;
- final float right =
- characterBounds[offset * 4 + 2] + viewportToContentHorizontalOffset;
- final float bottom =
- characterBounds[offset * 4 + 3] + viewportToContentVerticalOffset;
+ final float left = characterBounds[offset * 4];
+ final float top = characterBounds[offset * 4 + 1];
+ final float right = characterBounds[offset * 4 + 2];
+ final float bottom = characterBounds[offset * 4 + 3];
final boolean hasVisibleRegion = visibleRect.intersects(left, top, right, bottom);
final boolean hasInVisibleRegion = !visibleRect.contains(left, top, right, bottom);
@@ -12985,6 +12984,149 @@
}
/**
+ * Return the bounds of the characters in the given range, in TextView's coordinates.
+ *
+ * @param start the start index of the interested text range, inclusive.
+ * @param end the end index of the interested text range, exclusive.
+ * @param layoutLeft the left of the given {@code layout} in the editor view's coordinates.
+ * @param layoutTop the top of the given {@code layout} in the editor view's coordinates.
+ * @return the character bounds stored in a flattened array, in the editor view's coordinates.
+ */
+ private float[] getCharacterBounds(int start, int end, float layoutLeft, float layoutTop) {
+ final float[] characterBounds = new float[4 * (end - start)];
+ mLayout.fillCharacterBounds(start, end, characterBounds, 0);
+ for (int offset = 0; offset < end - start; ++offset) {
+ characterBounds[4 * offset] += layoutLeft;
+ characterBounds[4 * offset + 1] += layoutTop;
+ characterBounds[4 * offset + 2] += layoutLeft;
+ characterBounds[4 * offset + 3] += layoutTop;
+ }
+ return characterBounds;
+ }
+
+ /**
+ * Creates the {@link TextBoundsInfo} for the text lines that intersects with the {@code rectF}.
+ * @hide
+ */
+ public TextBoundsInfo getTextBoundsInfo(@NonNull RectF rectF) {
+ final Layout layout = getLayout();
+ if (layout == null) {
+ // No valid text layout, return null.
+ return null;
+ }
+ final CharSequence text = layout.getText();
+ if (text == null) {
+ // It's impossible that a layout has no text. Check here to avoid NPE.
+ return null;
+ }
+
+ final Matrix localToGlobalMatrix = new Matrix();
+ transformMatrixToGlobal(localToGlobalMatrix);
+ final Matrix globalToLocalMatrix = new Matrix();
+ if (!localToGlobalMatrix.invert(globalToLocalMatrix)) {
+ // Can't map global rectF to local coordinates, this is almost impossible in practice.
+ return null;
+ }
+
+ final float layoutLeft = viewportToContentHorizontalOffset();
+ final float layoutTop = viewportToContentVerticalOffset();
+
+ final RectF localRectF = new RectF(rectF);
+ globalToLocalMatrix.mapRect(localRectF);
+ localRectF.offset(-layoutLeft, -layoutTop);
+
+ // Text length is 0. There is no character bounds, return empty TextBoundsInfo.
+ // rectF doesn't intersect with the layout, return empty TextBoundsInfo.
+ if (!localRectF.intersects(0f, 0f, layout.getWidth(), layout.getHeight())
+ || text.length() == 0) {
+ final TextBoundsInfo.Builder builder = new TextBoundsInfo.Builder();
+ final SegmentFinder emptySegmentFinder =
+ new SegmentFinder.DefaultSegmentFinder(new int[0]);
+ builder.setStartAndEnd(0, 0)
+ .setMatrix(localToGlobalMatrix)
+ .setCharacterBounds(new float[0])
+ .setCharacterBidiLevel(new int[0])
+ .setCharacterFlags(new int[0])
+ .setGraphemeSegmentFinder(emptySegmentFinder)
+ .setLineSegmentFinder(emptySegmentFinder)
+ .setWordSegmentFinder(emptySegmentFinder);
+ return builder.build();
+ }
+
+ final int startLine = layout.getLineForVertical((int) Math.floor(localRectF.top));
+ final int endLine = layout.getLineForVertical((int) Math.floor(localRectF.bottom));
+ final int start = layout.getLineStart(startLine);
+ final int end = layout.getLineEnd(endLine);
+
+ // Compute character bounds.
+ final float[] characterBounds = getCharacterBounds(start, end, layoutLeft, layoutTop);
+
+ // Compute character flags and BiDi levels.
+ final int[] characterFlags = new int[end - start];
+ final int[] characterBidiLevels = new int[end - start];
+ for (int line = startLine; line <= endLine; ++line) {
+ final int lineStart = layout.getLineStart(line);
+ final int lineEnd = layout.getLineEnd(line);
+ final Layout.Directions directions = layout.getLineDirections(line);
+ for (int i = 0; i < directions.getRunCount(); ++i) {
+ final int runStart = directions.getRunStart(i) + lineStart;
+ final int runEnd = Math.min(runStart + directions.getRunLength(i), lineEnd);
+ final int runLevel = directions.getRunLevel(i);
+ Arrays.fill(characterBidiLevels, runStart - start, runEnd - start, runLevel);
+ }
+
+ final boolean lineIsRtl =
+ layout.getParagraphDirection(line) == Layout.DIR_RIGHT_TO_LEFT;
+ for (int index = lineStart; index < lineEnd; ++index) {
+ int flags = 0;
+ if (TextUtils.isWhitespace(text.charAt(index))) {
+ flags |= TextBoundsInfo.FLAG_CHARACTER_WHITESPACE;
+ }
+ if (TextUtils.isPunctuation(Character.codePointAt(text, index))) {
+ flags |= TextBoundsInfo.FLAG_CHARACTER_PUNCTUATION;
+ }
+ if (TextUtils.isNewline(Character.codePointAt(text, index))) {
+ flags |= TextBoundsInfo.FLAG_CHARACTER_LINEFEED;
+ }
+ if (lineIsRtl) {
+ flags |= TextBoundsInfo.FLAG_LINE_IS_RTL;
+ }
+ characterFlags[index - start] = flags;
+ }
+ }
+
+ // Create grapheme SegmentFinder.
+ final SegmentFinder graphemeSegmentFinder =
+ new GraphemeClusterSegmentFinder(text, layout.getPaint());
+
+ // Create word SegmentFinder.
+ final WordIterator wordIterator = getWordIterator();
+ wordIterator.setCharSequence(text, 0, text.length());
+ final SegmentFinder wordSegmentFinder = new WordSegmentFinder(text, wordIterator);
+
+ // Create line SegmentFinder.
+ final int lineCount = endLine - startLine + 1;
+ final int[] lineRanges = new int[2 * lineCount];
+ for (int line = startLine; line <= endLine; ++line) {
+ final int offset = line - startLine;
+ lineRanges[2 * offset] = layout.getLineStart(line);
+ lineRanges[2 * offset + 1] = layout.getLineEnd(line);
+ }
+ final SegmentFinder lineSegmentFinder = new SegmentFinder.DefaultSegmentFinder(lineRanges);
+
+ final TextBoundsInfo.Builder builder = new TextBoundsInfo.Builder();
+ builder.setStartAndEnd(start, end)
+ .setMatrix(localToGlobalMatrix)
+ .setCharacterBounds(characterBounds)
+ .setCharacterBidiLevel(characterBidiLevels)
+ .setCharacterFlags(characterFlags)
+ .setGraphemeSegmentFinder(graphemeSegmentFinder)
+ .setLineSegmentFinder(lineSegmentFinder)
+ .setWordSegmentFinder(wordSegmentFinder);
+ return builder.build();
+ }
+
+ /**
* @hide
*/
public boolean isPositionVisible(final float positionX, final float positionY) {
diff --git a/core/java/android/window/TransitionInfo.java b/core/java/android/window/TransitionInfo.java
index 8815ab3..0956a71 100644
--- a/core/java/android/window/TransitionInfo.java
+++ b/core/java/android/window/TransitionInfo.java
@@ -141,6 +141,10 @@
/** The first unused bit. This can be used by remotes to attach custom flags to this change. */
public static final int FLAG_FIRST_CUSTOM = 1 << 17;
+ /** The change belongs to a window that won't contain activities. */
+ public static final int FLAGS_IS_NON_APP_WINDOW =
+ FLAG_IS_WALLPAPER | FLAG_IS_INPUT_METHOD | FLAG_IS_SYSTEM_WINDOW;
+
/** @hide */
@IntDef(prefix = { "FLAG_" }, value = {
FLAG_NONE,
@@ -579,11 +583,16 @@
return mFlags;
}
- /** Whether the given change flags has included in this change. */
+ /** Whether this change contains any of the given change flags. */
public boolean hasFlags(@ChangeFlags int flags) {
return (mFlags & flags) != 0;
}
+ /** Whether this change contains all of the given change flags. */
+ public boolean hasAllFlags(@ChangeFlags int flags) {
+ return (mFlags & flags) == flags;
+ }
+
/**
* @return the bounds of the container before the change. It may be empty if the container
* is coming into existence.
diff --git a/core/java/com/android/internal/inputmethod/EditableInputConnection.java b/core/java/com/android/internal/inputmethod/EditableInputConnection.java
index f600c36..b155dd4 100644
--- a/core/java/com/android/internal/inputmethod/EditableInputConnection.java
+++ b/core/java/com/android/internal/inputmethod/EditableInputConnection.java
@@ -25,6 +25,7 @@
import android.annotation.CallbackExecutor;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.graphics.RectF;
import android.os.Bundle;
import android.text.Editable;
import android.text.Selection;
@@ -46,9 +47,12 @@
import android.view.inputmethod.RemoveSpaceGesture;
import android.view.inputmethod.SelectGesture;
import android.view.inputmethod.SelectRangeGesture;
+import android.view.inputmethod.TextBoundsInfo;
+import android.view.inputmethod.TextBoundsInfoResult;
import android.widget.TextView;
import java.util.concurrent.Executor;
+import java.util.function.Consumer;
import java.util.function.IntConsumer;
/**
@@ -262,6 +266,23 @@
}
@Override
+ public void requestTextBoundsInfo(
+ @NonNull RectF rectF, @Nullable @CallbackExecutor Executor executor,
+ @NonNull Consumer<TextBoundsInfoResult> consumer) {
+ final TextBoundsInfo textBoundsInfo = mTextView.getTextBoundsInfo(rectF);
+ final int resultCode;
+ if (textBoundsInfo != null) {
+ resultCode = TextBoundsInfoResult.CODE_SUCCESS;
+ } else {
+ resultCode = TextBoundsInfoResult.CODE_FAILED;
+ }
+ final TextBoundsInfoResult textBoundsInfoResult =
+ new TextBoundsInfoResult(resultCode, textBoundsInfo);
+
+ executor.execute(() -> consumer.accept(textBoundsInfoResult));
+ }
+
+ @Override
public boolean setImeConsumesInput(boolean imeConsumesInput) {
if (mTextView == null) {
return super.setImeConsumesInput(imeConsumesInput);
diff --git a/core/java/com/android/internal/inputmethod/IRemoteInputConnection.aidl b/core/java/com/android/internal/inputmethod/IRemoteInputConnection.aidl
index ea5c9a3..81e060d 100644
--- a/core/java/com/android/internal/inputmethod/IRemoteInputConnection.aidl
+++ b/core/java/com/android/internal/inputmethod/IRemoteInputConnection.aidl
@@ -16,20 +16,15 @@
package com.android.internal.inputmethod;
+import android.graphics.RectF;
import android.os.Bundle;
import android.os.ResultReceiver;
import android.view.KeyEvent;
import android.view.inputmethod.CompletionInfo;
import android.view.inputmethod.CorrectionInfo;
-import android.view.inputmethod.DeleteGesture;
-import android.view.inputmethod.DeleteRangeGesture;
import android.view.inputmethod.ExtractedTextRequest;
import android.view.inputmethod.InputContentInfo;
-import android.view.inputmethod.InsertGesture;
-import android.view.inputmethod.JoinOrSplitGesture;
-import android.view.inputmethod.RemoveSpaceGesture;
-import android.view.inputmethod.SelectGesture;
-import android.view.inputmethod.SelectRangeGesture;
+import android.view.inputmethod.ParcelableHandwritingGesture;
import android.view.inputmethod.TextAttribute;
import com.android.internal.infra.AndroidFuture;
@@ -94,26 +89,8 @@
void performPrivateCommand(in InputConnectionCommandHeader header, String action,
in Bundle data);
- void performHandwritingSelectGesture(in InputConnectionCommandHeader header,
- in SelectGesture gesture, in ResultReceiver resultReceiver);
-
- void performHandwritingSelectRangeGesture(in InputConnectionCommandHeader header,
- in SelectRangeGesture gesture, in ResultReceiver resultReceiver);
-
- void performHandwritingInsertGesture(in InputConnectionCommandHeader header,
- in InsertGesture gesture, in ResultReceiver resultReceiver);
-
- void performHandwritingDeleteGesture(in InputConnectionCommandHeader header,
- in DeleteGesture gesture, in ResultReceiver resultReceiver);
-
- void performHandwritingDeleteRangeGesture(in InputConnectionCommandHeader header,
- in DeleteRangeGesture gesture, in ResultReceiver resultReceiver);
-
- void performHandwritingRemoveSpaceGesture(in InputConnectionCommandHeader header,
- in RemoveSpaceGesture gesture, in ResultReceiver resultReceiver);
-
- void performHandwritingJoinOrSplitGesture(in InputConnectionCommandHeader header,
- in JoinOrSplitGesture gesture, in ResultReceiver resultReceiver);
+ void performHandwritingGesture(in InputConnectionCommandHeader header,
+ in ParcelableHandwritingGesture gesture, in ResultReceiver resultReceiver);
void setComposingRegion(in InputConnectionCommandHeader header, int start, int end);
@@ -130,6 +107,9 @@
int cursorUpdateMode, int cursorUpdateFilter, int imeDisplayId,
in AndroidFuture future /* T=Boolean */);
+ void requestTextBoundsInfo(in InputConnectionCommandHeader header, in RectF rect,
+ in ResultReceiver resultReceiver /* T=TextBoundsInfoResult */);
+
void commitContent(in InputConnectionCommandHeader header, in InputContentInfo inputContentInfo,
int flags, in Bundle opts, in AndroidFuture future /* T=Boolean */);
diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl
index 423642a..f7bb16e 100644
--- a/core/java/com/android/internal/view/IInputMethodManager.aidl
+++ b/core/java/com/android/internal/view/IInputMethodManager.aidl
@@ -147,9 +147,9 @@
boolean isStylusHandwritingAvailableAsUser(int userId);
/** add virtual stylus id for test Stylus handwriting session **/
- @EnforcePermission("INJECT_EVENTS")
+ @EnforcePermission("TEST_INPUT_METHOD")
@JavaPassthrough(annotation="@android.annotation.RequiresPermission(value = "
- + "android.Manifest.permission.INJECT_EVENTS)")
+ + "android.Manifest.permission.TEST_INPUT_METHOD)")
void addVirtualStylusIdForTestSession(in IInputMethodClient client);
/** Set a stylus idle-timeout after which handwriting {@code InkWindow} will be removed. */
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 62c5848..16e0a59 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1150,6 +1150,18 @@
android:description="@string/permdesc_readMediaImages"
android:protectionLevel="dangerous" />
+ <!-- Allows an application to read image or video files from external storage that a user has
+ selected via the permission prompt photo picker. Apps can check this permission to verify that
+ a user has decided to use the photo picker, instead of granting access to
+ {@link #READ_MEDIA_IMAGES or #READ_MEDIA_VIDEO}. It does not prevent apps from accessing the
+ standard photo picker manually.
+ <p>Protection level: dangerous -->
+ <permission android:name="android.permission.READ_MEDIA_VISUAL_USER_SELECTED"
+ android:permissionGroup="android.permission-group.UNDEFINED"
+ android:label="@string/permlab_readVisualUserSelect"
+ android:description="@string/permdesc_readVisualUserSelect"
+ android:protectionLevel="dangerous" />
+
<!-- Allows an application to write to external storage.
<p><strong>Note: </strong>If your app targets {@link android.os.Build.VERSION_CODES#R} or
higher, this permission has no effect.
@@ -3152,6 +3164,12 @@
<permission android:name="android.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND"
android:protectionLevel="signature|privileged|vendorPrivileged|oem|verifier|role"/>
+ <!-- Allows an application to hint that a broadcast is associated with an
+ "interactive" usage scenario
+ @hide -->
+ <permission android:name="android.permission.BROADCAST_OPTION_INTERACTIVE"
+ android:protectionLevel="signature|privileged" />
+
<!-- @SystemApi Must be required by activities that handle the intent action
{@link Intent#ACTION_SEND_SHOW_SUSPENDED_APP_DETAILS}. This is for use by apps that
hold {@link Manifest.permission#SUSPEND_APPS} to interact with the system.
@@ -4127,7 +4145,8 @@
android:protectionLevel="signature" />
<!-- Allows access to Test APIs defined in {@link android.view.inputmethod.InputMethodManager}.
- @hide -->
+ @hide
+ @TestApi -->
<permission android:name="android.permission.TEST_INPUT_METHOD"
android:protectionLevel="signature" />
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 0ebce40..b20bfef 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -72,6 +72,10 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"Beller-ID se verstek is nie beperk nie. Volgende oproep: nie beperk nie"</string>
<string name="serviceNotProvisioned" msgid="8289333510236766193">"Diens nie verskaf nie."</string>
<string name="CLIRPermanent" msgid="166443681876381118">"Jy kan nie die beller-ID-instelling verander nie."</string>
+ <!-- no translation found for auto_data_switch_title (3286350716870518297) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_content (803557715007110959) -->
+ <skip />
<string name="RestrictedOnDataTitle" msgid="1500576417268169774">"Geen mobiele datadiens nie"</string>
<string name="RestrictedOnEmergencyTitle" msgid="2852916906106191866">"Noodoproepe is onbeskikbaar"</string>
<string name="RestrictedOnNormalTitle" msgid="7009474589746551737">"Geen stemdiens nie"</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index a861f3c..2574fd8 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -72,6 +72,10 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"የደዋይ ID ነባሪዎች ወደአልተከለከለም። ቀጥሎ ጥሪ፡አልተከለከለም"</string>
<string name="serviceNotProvisioned" msgid="8289333510236766193">"አገልግሎት አልቀረበም።"</string>
<string name="CLIRPermanent" msgid="166443681876381118">"የደዋይ መታወቂያ ቅንብሮች መለወጥ አትችልም፡፡"</string>
+ <!-- no translation found for auto_data_switch_title (3286350716870518297) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_content (803557715007110959) -->
+ <skip />
<string name="RestrictedOnDataTitle" msgid="1500576417268169774">"ምንም የተንቀሳቃሽ ስልክ ውሂብ አገልግሎት የለም"</string>
<string name="RestrictedOnEmergencyTitle" msgid="2852916906106191866">"የድንገተኛ አደጋ ጥሪ አይገኝም"</string>
<string name="RestrictedOnNormalTitle" msgid="7009474589746551737">"ምንም የድምፅ ጥሪ አገልግሎት የለም"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 7623fb1..ba3ebb1 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -76,6 +76,10 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"الإعداد التلقائي لمعرف المتصل هو غير محظور . الاتصال التالي: غير محظور"</string>
<string name="serviceNotProvisioned" msgid="8289333510236766193">"الخدمة غير متوفرة."</string>
<string name="CLIRPermanent" msgid="166443681876381118">"لا يمكنك تغيير إعداد معرّف المتصل."</string>
+ <!-- no translation found for auto_data_switch_title (3286350716870518297) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_content (803557715007110959) -->
+ <skip />
<string name="RestrictedOnDataTitle" msgid="1500576417268169774">"لا تتوفّر خدمة بيانات جوّال."</string>
<string name="RestrictedOnEmergencyTitle" msgid="2852916906106191866">"لا تتوفّر مكالمات طوارئ."</string>
<string name="RestrictedOnNormalTitle" msgid="7009474589746551737">"لا تتوفر خدمة صوتية"</string>
diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml
index 3a97baf..d49d3b1 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -72,6 +72,10 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"কলাৰ আইডি সীমিত নকৰিবলৈ পূর্বনির্ধাৰণ কৰা হৈছে। পৰৱৰ্তী কল: সীমিত কৰা হোৱা নাই"</string>
<string name="serviceNotProvisioned" msgid="8289333510236766193">"সুবিধা যোগান ধৰা হোৱা নাই।"</string>
<string name="CLIRPermanent" msgid="166443681876381118">"আপুনি কলাৰ আইডি ছেটিং সলনি কৰিব নোৱাৰে।"</string>
+ <!-- no translation found for auto_data_switch_title (3286350716870518297) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_content (803557715007110959) -->
+ <skip />
<string name="RestrictedOnDataTitle" msgid="1500576417268169774">"কোনো ম’বাইল ডেটা সেৱা নাই"</string>
<string name="RestrictedOnEmergencyTitle" msgid="2852916906106191866">"জৰুৰীকালীন কল কৰাৰ সুবিধা উপলব্ধ নহয়"</string>
<string name="RestrictedOnNormalTitle" msgid="7009474589746551737">"কোনো ভইচ সেৱা নাই"</string>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index 0b361ac..ffd1480 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -72,6 +72,10 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"Zəng edənin kimliyi defolt olaraq qadağan deyil. Növbəti zəng: Qadağan deyil"</string>
<string name="serviceNotProvisioned" msgid="8289333510236766193">"Xidmət təmin edilməyib."</string>
<string name="CLIRPermanent" msgid="166443681876381118">"Çağrı kimliyi ayarını dəyişə bilməzsiniz."</string>
+ <!-- no translation found for auto_data_switch_title (3286350716870518297) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_content (803557715007110959) -->
+ <skip />
<string name="RestrictedOnDataTitle" msgid="1500576417268169774">"Mobil data xidməti yoxdur"</string>
<string name="RestrictedOnEmergencyTitle" msgid="2852916906106191866">"Təcili zəng əlçatan deyil"</string>
<string name="RestrictedOnNormalTitle" msgid="7009474589746551737">"Səsli xidmət yoxdur"</string>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index 078c098..b1ec940b 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -73,6 +73,10 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"ID pozivaoca podrazumevano nije ograničen. Sledeći poziv: Nije ograničen."</string>
<string name="serviceNotProvisioned" msgid="8289333510236766193">"Usluga nije dobavljena."</string>
<string name="CLIRPermanent" msgid="166443681876381118">"Ne možete da promenite podešavanje ID-a korisnika."</string>
+ <!-- no translation found for auto_data_switch_title (3286350716870518297) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_content (803557715007110959) -->
+ <skip />
<string name="RestrictedOnDataTitle" msgid="1500576417268169774">"Nema usluge mobilnih podataka"</string>
<string name="RestrictedOnEmergencyTitle" msgid="2852916906106191866">"Hitni pozivi nisu dostupni"</string>
<string name="RestrictedOnNormalTitle" msgid="7009474589746551737">"Nema glasovne usluge"</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index 023e82c..40605c5 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -74,6 +74,10 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"Налады ідэнтыфікатару АВН па змаўчанні: не абмяжавана. Наступны выклік: не абмежавана"</string>
<string name="serviceNotProvisioned" msgid="8289333510236766193">"Служба не прадастаўляецца."</string>
<string name="CLIRPermanent" msgid="166443681876381118">"Вы не можаце змяніць налады ідэнтыфікатара абанента, якi тэлефануе."</string>
+ <!-- no translation found for auto_data_switch_title (3286350716870518297) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_content (803557715007110959) -->
+ <skip />
<string name="RestrictedOnDataTitle" msgid="1500576417268169774">"Мабільная перадача даных недаступная"</string>
<string name="RestrictedOnEmergencyTitle" msgid="2852916906106191866">"Экстранныя выклікі недаступныя"</string>
<string name="RestrictedOnNormalTitle" msgid="7009474589746551737">"Няма сэрвісу галасавых выклікаў"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index aaa080a..a1c9d1c 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -72,6 +72,10 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"Стандартната идентификация на повикванията е „разрешено“. За следващото обаждане тя е разрешена."</string>
<string name="serviceNotProvisioned" msgid="8289333510236766193">"Услугата не е обезпечена."</string>
<string name="CLIRPermanent" msgid="166443681876381118">"Не можете да променяте настройката за идентификация на обажданията."</string>
+ <!-- no translation found for auto_data_switch_title (3286350716870518297) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_content (803557715007110959) -->
+ <skip />
<string name="RestrictedOnDataTitle" msgid="1500576417268169774">"Няма достъп до мобилната услуга за данни"</string>
<string name="RestrictedOnEmergencyTitle" msgid="2852916906106191866">"Няма достъп до спешните обаждания"</string>
<string name="RestrictedOnNormalTitle" msgid="7009474589746551737">"Няма услуга за гласови обаждания"</string>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index ee1db8e..fd69acd 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -72,6 +72,10 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"ডিফল্টরূপে কলার আইডি সীমাবদ্ধ করা থাকে না৷ পরবর্তী কল: সীমাবদ্ধ নয়"</string>
<string name="serviceNotProvisioned" msgid="8289333510236766193">"পরিষেবা প্রস্তুত নয়৷"</string>
<string name="CLIRPermanent" msgid="166443681876381118">"আপনি কলার আইডি এর সেটিংস পরিবর্তন করতে পারবেন না৷"</string>
+ <!-- no translation found for auto_data_switch_title (3286350716870518297) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_content (803557715007110959) -->
+ <skip />
<string name="RestrictedOnDataTitle" msgid="1500576417268169774">"মোবাইল ডেটা পরিষেবা নেই"</string>
<string name="RestrictedOnEmergencyTitle" msgid="2852916906106191866">"জরুরি কল করা যাবে না"</string>
<string name="RestrictedOnNormalTitle" msgid="7009474589746551737">"ভয়েস পরিষেবা নেই"</string>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index 20f6bc1..455c9e9 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -73,6 +73,8 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"Prikaz ID-a pozivaoca u zadanim postavkama nije zabranjen. Sljedeći poziv: nije zabranjen"</string>
<string name="serviceNotProvisioned" msgid="8289333510236766193">"Uslugu nije moguće koristiti."</string>
<string name="CLIRPermanent" msgid="166443681876381118">"Ne možete promijeniti postavke ID-a pozivaoca."</string>
+ <string name="auto_data_switch_title" msgid="3286350716870518297">"Podaci su prebačeni na <xliff:g id="CARRIERDISPLAY">%s</xliff:g>"</string>
+ <string name="auto_data_switch_content" msgid="803557715007110959">"To uvijek možete promijeniti u postavkama"</string>
<string name="RestrictedOnDataTitle" msgid="1500576417268169774">"Nema usluge prijenosa podataka na mobilnoj mreži"</string>
<string name="RestrictedOnEmergencyTitle" msgid="2852916906106191866">"Hitni pozivi su nedostupni"</string>
<string name="RestrictedOnNormalTitle" msgid="7009474589746551737">"Nema usluge govornih poziva"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 2142b60..43dc676 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -72,6 +72,10 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"El valor predeterminat de l\'identificador de trucada és no restringit. Trucada següent: no restringit"</string>
<string name="serviceNotProvisioned" msgid="8289333510236766193">"No s\'ha proveït el servei."</string>
<string name="CLIRPermanent" msgid="166443681876381118">"No pots canviar la configuració de l\'identificador de trucada."</string>
+ <!-- no translation found for auto_data_switch_title (3286350716870518297) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_content (803557715007110959) -->
+ <skip />
<string name="RestrictedOnDataTitle" msgid="1500576417268169774">"No hi ha servei de dades mòbils"</string>
<string name="RestrictedOnEmergencyTitle" msgid="2852916906106191866">"Les trucades d\'emergència no estan disponibles"</string>
<string name="RestrictedOnNormalTitle" msgid="7009474589746551737">"Sense servei de veu"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 7720d08..132a9f5 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -74,6 +74,10 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"Ve výchozím nastavení není funkce ID volajícího omezena. Příští hovor: Neomezeno"</string>
<string name="serviceNotProvisioned" msgid="8289333510236766193">"Služba není zřízena."</string>
<string name="CLIRPermanent" msgid="166443681876381118">"Nastavení ID volajícího nesmíte měnit."</string>
+ <!-- no translation found for auto_data_switch_title (3286350716870518297) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_content (803557715007110959) -->
+ <skip />
<string name="RestrictedOnDataTitle" msgid="1500576417268169774">"Není k dispozici žádná mobilní datová služba"</string>
<string name="RestrictedOnEmergencyTitle" msgid="2852916906106191866">"Tísňová volání jsou nedostupná"</string>
<string name="RestrictedOnNormalTitle" msgid="7009474589746551737">"Hlasová volání nejsou k dispozici"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index ecd6407..9dd4334 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -72,6 +72,8 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"Standarder for opkalds-id til ikke begrænset. Næste opkald: Ikke begrænset"</string>
<string name="serviceNotProvisioned" msgid="8289333510236766193">"Tjenesten provisioneres ikke."</string>
<string name="CLIRPermanent" msgid="166443681876381118">"Du kan ikke ændre indstillingen for opkalds-id\'et."</string>
+ <string name="auto_data_switch_title" msgid="3286350716870518297">"Der blev skiftet til <xliff:g id="CARRIERDISPLAY">%s</xliff:g>-data"</string>
+ <string name="auto_data_switch_content" msgid="803557715007110959">"Du kan altid ændre dette under Indstillinger"</string>
<string name="RestrictedOnDataTitle" msgid="1500576417268169774">"Ingen mobildatatjeneste"</string>
<string name="RestrictedOnEmergencyTitle" msgid="2852916906106191866">"Det er ikke muligt at foretage nødopkald"</string>
<string name="RestrictedOnNormalTitle" msgid="7009474589746551737">"Ingen taletjeneste"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 3d5985c9..661c2cd 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -72,6 +72,10 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"Anrufer-ID ist standardmäßig nicht beschränkt. Nächster Anruf: Nicht beschränkt"</string>
<string name="serviceNotProvisioned" msgid="8289333510236766193">"Dienst nicht eingerichtet."</string>
<string name="CLIRPermanent" msgid="166443681876381118">"Du kannst die Einstellung für die Anrufer-ID nicht ändern."</string>
+ <!-- no translation found for auto_data_switch_title (3286350716870518297) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_content (803557715007110959) -->
+ <skip />
<string name="RestrictedOnDataTitle" msgid="1500576417268169774">"Kein mobiler Datendienst"</string>
<string name="RestrictedOnEmergencyTitle" msgid="2852916906106191866">"Notrufe nicht möglich"</string>
<string name="RestrictedOnNormalTitle" msgid="7009474589746551737">"Keine Anrufe"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index f84a9fb..8cb3989b 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -72,6 +72,8 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"Η αναγνώριση κλήσης βρίσκεται από προεπιλογή στην \"μη περιορισμένη\". Επόμενη κλήση: Μη περιορισμένη"</string>
<string name="serviceNotProvisioned" msgid="8289333510236766193">"Η υπηρεσία δεν προβλέπεται."</string>
<string name="CLIRPermanent" msgid="166443681876381118">"Δεν μπορείτε να αλλάξετε τη ρύθμιση του αναγνωριστικού καλούντος."</string>
+ <string name="auto_data_switch_title" msgid="3286350716870518297">"Έγινε εναλλαγή των δεδομένων σε <xliff:g id="CARRIERDISPLAY">%s</xliff:g>"</string>
+ <string name="auto_data_switch_content" msgid="803557715007110959">"Μπορείτε να αλλάξετε αυτήν την επιλογή ανά πάσα στιγμή στις Ρυθμίσεις"</string>
<string name="RestrictedOnDataTitle" msgid="1500576417268169774">"Δεν υπάρχει υπηρεσία δεδομένων κινητής τηλεφωνίας"</string>
<string name="RestrictedOnEmergencyTitle" msgid="2852916906106191866">"Οι κλήσεις έκτακτης ανάγκης δεν είναι διαθέσιμες"</string>
<string name="RestrictedOnNormalTitle" msgid="7009474589746551737">"Δεν υπάρχει φωνητική υπηρεσία"</string>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index 4c0510b..75db3826 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -72,6 +72,8 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"Caller ID defaults to not restricted. Next call: Not restricted"</string>
<string name="serviceNotProvisioned" msgid="8289333510236766193">"Service not provisioned."</string>
<string name="CLIRPermanent" msgid="166443681876381118">"You can\'t change the caller ID setting."</string>
+ <string name="auto_data_switch_title" msgid="3286350716870518297">"Switched data to <xliff:g id="CARRIERDISPLAY">%s</xliff:g>"</string>
+ <string name="auto_data_switch_content" msgid="803557715007110959">"You can change this at any time in Settings"</string>
<string name="RestrictedOnDataTitle" msgid="1500576417268169774">"No mobile data service"</string>
<string name="RestrictedOnEmergencyTitle" msgid="2852916906106191866">"Emergency calling unavailable"</string>
<string name="RestrictedOnNormalTitle" msgid="7009474589746551737">"No voice service"</string>
diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml
index 875ddf9..883cd55 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -72,6 +72,8 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"Caller ID defaults to not restricted. Next call: Not restricted"</string>
<string name="serviceNotProvisioned" msgid="8289333510236766193">"Service not provisioned."</string>
<string name="CLIRPermanent" msgid="166443681876381118">"You can\'t change the caller ID setting."</string>
+ <string name="auto_data_switch_title" msgid="3286350716870518297">"Switched data to <xliff:g id="CARRIERDISPLAY">%s</xliff:g>"</string>
+ <string name="auto_data_switch_content" msgid="803557715007110959">"You can change this at any time in Settings"</string>
<string name="RestrictedOnDataTitle" msgid="1500576417268169774">"No mobile data service"</string>
<string name="RestrictedOnEmergencyTitle" msgid="2852916906106191866">"Emergency calling unavailable"</string>
<string name="RestrictedOnNormalTitle" msgid="7009474589746551737">"No voice service"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 6e034b7..c4c19da 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -72,6 +72,8 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"Caller ID defaults to not restricted. Next call: Not restricted"</string>
<string name="serviceNotProvisioned" msgid="8289333510236766193">"Service not provisioned."</string>
<string name="CLIRPermanent" msgid="166443681876381118">"You can\'t change the caller ID setting."</string>
+ <string name="auto_data_switch_title" msgid="3286350716870518297">"Switched data to <xliff:g id="CARRIERDISPLAY">%s</xliff:g>"</string>
+ <string name="auto_data_switch_content" msgid="803557715007110959">"You can change this at any time in Settings"</string>
<string name="RestrictedOnDataTitle" msgid="1500576417268169774">"No mobile data service"</string>
<string name="RestrictedOnEmergencyTitle" msgid="2852916906106191866">"Emergency calling unavailable"</string>
<string name="RestrictedOnNormalTitle" msgid="7009474589746551737">"No voice service"</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 643f27f..d19199d 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -72,6 +72,8 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"Caller ID defaults to not restricted. Next call: Not restricted"</string>
<string name="serviceNotProvisioned" msgid="8289333510236766193">"Service not provisioned."</string>
<string name="CLIRPermanent" msgid="166443681876381118">"You can\'t change the caller ID setting."</string>
+ <string name="auto_data_switch_title" msgid="3286350716870518297">"Switched data to <xliff:g id="CARRIERDISPLAY">%s</xliff:g>"</string>
+ <string name="auto_data_switch_content" msgid="803557715007110959">"You can change this at any time in Settings"</string>
<string name="RestrictedOnDataTitle" msgid="1500576417268169774">"No mobile data service"</string>
<string name="RestrictedOnEmergencyTitle" msgid="2852916906106191866">"Emergency calling unavailable"</string>
<string name="RestrictedOnNormalTitle" msgid="7009474589746551737">"No voice service"</string>
diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml
index 91e99ff..9037d70 100644
--- a/core/res/res/values-en-rXC/strings.xml
+++ b/core/res/res/values-en-rXC/strings.xml
@@ -72,6 +72,8 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"Caller ID defaults to not restricted. Next call: Not restricted"</string>
<string name="serviceNotProvisioned" msgid="8289333510236766193">"Service not provisioned."</string>
<string name="CLIRPermanent" msgid="166443681876381118">"You can\'t change the caller ID setting."</string>
+ <string name="auto_data_switch_title" msgid="3286350716870518297">"Switched data to <xliff:g id="CARRIERDISPLAY">%s</xliff:g>"</string>
+ <string name="auto_data_switch_content" msgid="803557715007110959">"You can change this anytime in Settings"</string>
<string name="RestrictedOnDataTitle" msgid="1500576417268169774">"No mobile data service"</string>
<string name="RestrictedOnEmergencyTitle" msgid="2852916906106191866">"Emergency calling unavailable"</string>
<string name="RestrictedOnNormalTitle" msgid="7009474589746551737">"No voice service"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 6a45205..9441f27 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -73,6 +73,10 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"El Identificador de llamadas está predeterminado en no restringido. Llamada siguiente: no restringido"</string>
<string name="serviceNotProvisioned" msgid="8289333510236766193">"Servicio no suministrado."</string>
<string name="CLIRPermanent" msgid="166443681876381118">"No puedes cambiar la configuración del identificador de llamadas."</string>
+ <!-- no translation found for auto_data_switch_title (3286350716870518297) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_content (803557715007110959) -->
+ <skip />
<string name="RestrictedOnDataTitle" msgid="1500576417268169774">"No hay ningún servicio de datos móviles"</string>
<string name="RestrictedOnEmergencyTitle" msgid="2852916906106191866">"Servicio de llamadas de emergencia no disponible"</string>
<string name="RestrictedOnNormalTitle" msgid="7009474589746551737">"Sin servicio de voz"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 66f67b3..753aa8b 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -73,6 +73,10 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"La identificación del emisor presenta el valor predeterminado de no restringido. Siguiente llamada: No restringido"</string>
<string name="serviceNotProvisioned" msgid="8289333510236766193">"El servicio no se suministra."</string>
<string name="CLIRPermanent" msgid="166443681876381118">"No puedes modificar la identificación de emisor."</string>
+ <!-- no translation found for auto_data_switch_title (3286350716870518297) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_content (803557715007110959) -->
+ <skip />
<string name="RestrictedOnDataTitle" msgid="1500576417268169774">"No hay ningún servicio de datos móviles"</string>
<string name="RestrictedOnEmergencyTitle" msgid="2852916906106191866">"Servicio de llamadas de emergencia no disponible"</string>
<string name="RestrictedOnNormalTitle" msgid="7009474589746551737">"Sin servicio de voz"</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 349a6b2..1789793 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -72,6 +72,10 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"Helistaja ID pole vaikimisi piiratud. Järgmine kõne: pole piiratud"</string>
<string name="serviceNotProvisioned" msgid="8289333510236766193">"Teenus pole ette valmistatud."</string>
<string name="CLIRPermanent" msgid="166443681876381118">"Helistaja ID seadet ei saa muuta."</string>
+ <!-- no translation found for auto_data_switch_title (3286350716870518297) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_content (803557715007110959) -->
+ <skip />
<string name="RestrictedOnDataTitle" msgid="1500576417268169774">"Mobiilne andmesideteenus puudub"</string>
<string name="RestrictedOnEmergencyTitle" msgid="2852916906106191866">"Hädaabikõned pole saadaval"</string>
<string name="RestrictedOnNormalTitle" msgid="7009474589746551737">"Häälkõned pole saadaval"</string>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index d4759d5..8a7d073 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -72,6 +72,10 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"Deitzailearen identitatea zerbitzuaren balio lehenetsiak ez du murriztapenik ezartzen. Hurrengo deia: murriztapenik gabe."</string>
<string name="serviceNotProvisioned" msgid="8289333510236766193">"Zerbitzua ez da hornitu."</string>
<string name="CLIRPermanent" msgid="166443681876381118">"Ezin duzu aldatu deitzailearen identitatearen ezarpena."</string>
+ <!-- no translation found for auto_data_switch_title (3286350716870518297) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_content (803557715007110959) -->
+ <skip />
<string name="RestrictedOnDataTitle" msgid="1500576417268169774">"Ez dago mugikorreko datu-zerbitzurik"</string>
<string name="RestrictedOnEmergencyTitle" msgid="2852916906106191866">"Ezin da egin larrialdi-deirik"</string>
<string name="RestrictedOnNormalTitle" msgid="7009474589746551737">"Ez dago ahots-deien zerbitzurik"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 4064353..88bbcc6 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -72,6 +72,10 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"پیشفرض شناسه تماسگیرنده روی غیرمحدود است. تماس بعدی: بدون محدودیت"</string>
<string name="serviceNotProvisioned" msgid="8289333510236766193">"سرویس دارای مجوز نیست."</string>
<string name="CLIRPermanent" msgid="166443681876381118">"شما میتوانید تنظیم شناسه تماسگیرنده را تغییر دهید."</string>
+ <!-- no translation found for auto_data_switch_title (3286350716870518297) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_content (803557715007110959) -->
+ <skip />
<string name="RestrictedOnDataTitle" msgid="1500576417268169774">"بدون سرویس داده تلفن همراه"</string>
<string name="RestrictedOnEmergencyTitle" msgid="2852916906106191866">"تماس اضطراری دردسترس نیست"</string>
<string name="RestrictedOnNormalTitle" msgid="7009474589746551737">"سرویس صوتی دردسترس نیست"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 8fedfb7..da3a91e 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -72,6 +72,10 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"Soittajan tunnukseksi muutetaan rajoittamaton. Seuraava puhelu: ei rajoitettu"</string>
<string name="serviceNotProvisioned" msgid="8289333510236766193">"Palvelua ei tarjota."</string>
<string name="CLIRPermanent" msgid="166443681876381118">"Et voi muuttaa soittajan tunnuksen asetusta."</string>
+ <!-- no translation found for auto_data_switch_title (3286350716870518297) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_content (803557715007110959) -->
+ <skip />
<string name="RestrictedOnDataTitle" msgid="1500576417268169774">"Ei mobiilidatapalvelua"</string>
<string name="RestrictedOnEmergencyTitle" msgid="2852916906106191866">"Hätäpuhelut eivät ole käytettävissä"</string>
<string name="RestrictedOnNormalTitle" msgid="7009474589746551737">"Ei äänipuheluja"</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index e63b734..d05d97b 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -73,6 +73,10 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"Par défaut, les numéros des appelants ne sont pas restreints. Appel suivant : non restreint"</string>
<string name="serviceNotProvisioned" msgid="8289333510236766193">"Ce service n\'est pas pris en charge."</string>
<string name="CLIRPermanent" msgid="166443681876381118">"Impossible de modifier le paramètre relatif au numéro de l\'appelant."</string>
+ <!-- no translation found for auto_data_switch_title (3286350716870518297) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_content (803557715007110959) -->
+ <skip />
<string name="RestrictedOnDataTitle" msgid="1500576417268169774">"Aucun service de données cellulaires"</string>
<string name="RestrictedOnEmergencyTitle" msgid="2852916906106191866">"Le service d\'appel d\'urgence n\'est pas accessible"</string>
<string name="RestrictedOnNormalTitle" msgid="7009474589746551737">"Aucun service vocal"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 019fdf2..cb2e201 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -73,6 +73,10 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"Par défaut, les numéros des appelants ne sont pas restreints. Appel suivant : non restreint"</string>
<string name="serviceNotProvisioned" msgid="8289333510236766193">"Ce service n\'est pas pris en charge."</string>
<string name="CLIRPermanent" msgid="166443681876381118">"Impossible de modifier le paramètre relatif au numéro de l\'appelant."</string>
+ <!-- no translation found for auto_data_switch_title (3286350716870518297) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_content (803557715007110959) -->
+ <skip />
<string name="RestrictedOnDataTitle" msgid="1500576417268169774">"Aucun service de données mobiles"</string>
<string name="RestrictedOnEmergencyTitle" msgid="2852916906106191866">"Appels d\'urgence non disponibles"</string>
<string name="RestrictedOnNormalTitle" msgid="7009474589746551737">"Aucun service vocal"</string>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index 219299f..a3aed41 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -72,6 +72,10 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"O valor predeterminado do identificador de chamada é restrinxido. Próxima chamada: non restrinxido"</string>
<string name="serviceNotProvisioned" msgid="8289333510236766193">"Servizo non ofrecido."</string>
<string name="CLIRPermanent" msgid="166443681876381118">"Non podes cambiar a configuración do identificador de chamada."</string>
+ <!-- no translation found for auto_data_switch_title (3286350716870518297) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_content (803557715007110959) -->
+ <skip />
<string name="RestrictedOnDataTitle" msgid="1500576417268169774">"Non hai servizo de datos para móbiles"</string>
<string name="RestrictedOnEmergencyTitle" msgid="2852916906106191866">"As chamadas de emerxencia non están dispoñibles"</string>
<string name="RestrictedOnNormalTitle" msgid="7009474589746551737">"Non hai servizo de chamadas de voz"</string>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index 90dda1a..2d9210b 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -72,6 +72,10 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"કૉલર ID પ્રતિબંધિત નહીં પર ડિફોલ્ટ છે. આગલો કૉલ: પ્રતિબંધિત નહીં"</string>
<string name="serviceNotProvisioned" msgid="8289333510236766193">"સેવાની જોગવાઈ કરી નથી."</string>
<string name="CLIRPermanent" msgid="166443681876381118">"તમે કૉલર ID સેટિંગ બદલી શકતાં નથી."</string>
+ <!-- no translation found for auto_data_switch_title (3286350716870518297) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_content (803557715007110959) -->
+ <skip />
<string name="RestrictedOnDataTitle" msgid="1500576417268169774">"કોઈ મોબાઇલ ડેટા સેવા નથી"</string>
<string name="RestrictedOnEmergencyTitle" msgid="2852916906106191866">"કોટોકટીની કૉલિંગ સેવા અનુપલબ્ધ"</string>
<string name="RestrictedOnNormalTitle" msgid="7009474589746551737">"કોઈ વૉઇસ સેવા નથી"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index af5bc1f..9f0e936 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -72,6 +72,10 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"कॉलर आईडी डिफ़ॉल्ट रूप से सीमित नहीं है. अगली कॉल: सीमित नहीं"</string>
<string name="serviceNotProvisioned" msgid="8289333510236766193">"सेवा प्रावधान की हुई नहीं है."</string>
<string name="CLIRPermanent" msgid="166443681876381118">"आप कॉलर आईडी सेटिंग नहीं बदल सकते."</string>
+ <!-- no translation found for auto_data_switch_title (3286350716870518297) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_content (803557715007110959) -->
+ <skip />
<string name="RestrictedOnDataTitle" msgid="1500576417268169774">"मोबाइल डेटा सेवा पर रोक लगा दी गई है"</string>
<string name="RestrictedOnEmergencyTitle" msgid="2852916906106191866">"आपातकालीन कॉल पर रोक लगा दी गई है"</string>
<string name="RestrictedOnNormalTitle" msgid="7009474589746551737">"कोई वॉइस सेवा नहीं है"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 87df29a..40a49db 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -73,6 +73,8 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"Zadana postavka ID-a pozivatelja nema ograničenje. Sljedeći poziv: Nije ograničen"</string>
<string name="serviceNotProvisioned" msgid="8289333510236766193">"Usluga nije rezervirana."</string>
<string name="CLIRPermanent" msgid="166443681876381118">"Ne možete promijeniti postavku ID-a pozivatelja."</string>
+ <string name="auto_data_switch_title" msgid="3286350716870518297">"Podaci su prebačeni na <xliff:g id="CARRIERDISPLAY">%s</xliff:g>"</string>
+ <string name="auto_data_switch_content" msgid="803557715007110959">"To uvijek možete promijeniti u postavkama"</string>
<string name="RestrictedOnDataTitle" msgid="1500576417268169774">"Nema podatkovne mobilne usluge"</string>
<string name="RestrictedOnEmergencyTitle" msgid="2852916906106191866">"Hitni pozivi nisu dostupni"</string>
<string name="RestrictedOnNormalTitle" msgid="7009474589746551737">"Nema glasovnih usluga"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 3762fde..cf6132f 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -72,6 +72,10 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"A hívóazonosító alapértelmezett értéke nem korlátozott. Következő hívás: nem korlátozott"</string>
<string name="serviceNotProvisioned" msgid="8289333510236766193">"A szolgáltatás nincs biztosítva."</string>
<string name="CLIRPermanent" msgid="166443681876381118">"Nem tudja módosítani a hívó fél azonosítója beállítást."</string>
+ <!-- no translation found for auto_data_switch_title (3286350716870518297) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_content (803557715007110959) -->
+ <skip />
<string name="RestrictedOnDataTitle" msgid="1500576417268169774">"Nincs mobiladat-szolgáltatás"</string>
<string name="RestrictedOnEmergencyTitle" msgid="2852916906106191866">"Segélyhívás nem lehetséges"</string>
<string name="RestrictedOnNormalTitle" msgid="7009474589746551737">"Hangszolgáltatás letiltva"</string>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index a11e24b..4da9e3b 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -72,6 +72,10 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"Զանգողի ID-ն լռելյայն չսահմանափակված է: Հաջորդ զանգը` չսահմանափակված"</string>
<string name="serviceNotProvisioned" msgid="8289333510236766193">"Ծառայությունը չի տրամադրվում:"</string>
<string name="CLIRPermanent" msgid="166443681876381118">"Դուք չեք կարող փոխել զանգողի ID-ի կարգավորումները:"</string>
+ <!-- no translation found for auto_data_switch_title (3286350716870518297) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_content (803557715007110959) -->
+ <skip />
<string name="RestrictedOnDataTitle" msgid="1500576417268169774">"Բջջային ինտերնետի ծառայությունն արգելափակված է"</string>
<string name="RestrictedOnEmergencyTitle" msgid="2852916906106191866">"Շտապ կանչերը հասանելի չեն"</string>
<string name="RestrictedOnNormalTitle" msgid="7009474589746551737">"Ձայնային ծառայությունն անհասանելի է"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index dbccee9..2f2e524 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -72,6 +72,10 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"ID penelepon diatur default ke tidak dibatasi. Panggilan selanjutnya: Tidak dibatasi"</string>
<string name="serviceNotProvisioned" msgid="8289333510236766193">"Layanan tidak diperlengkapi."</string>
<string name="CLIRPermanent" msgid="166443681876381118">"Anda tidak dapat mengubah setelan ID penelepon."</string>
+ <!-- no translation found for auto_data_switch_title (3286350716870518297) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_content (803557715007110959) -->
+ <skip />
<string name="RestrictedOnDataTitle" msgid="1500576417268169774">"Tidak ada layanan data seluler"</string>
<string name="RestrictedOnEmergencyTitle" msgid="2852916906106191866">"Panggilan darurat tidak tersedia"</string>
<string name="RestrictedOnNormalTitle" msgid="7009474589746551737">"Tidak ada layanan panggilan suara"</string>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index cfefc03..82a1b66 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -72,6 +72,10 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"Númerabirting er sjálfgefið án takmarkana. Næsta símtal: Án takmarkana"</string>
<string name="serviceNotProvisioned" msgid="8289333510236766193">"Þjónustu ekki útdeilt."</string>
<string name="CLIRPermanent" msgid="166443681876381118">"Þú getur ekki breytt stillingu númerabirtingar."</string>
+ <!-- no translation found for auto_data_switch_title (3286350716870518297) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_content (803557715007110959) -->
+ <skip />
<string name="RestrictedOnDataTitle" msgid="1500576417268169774">"Engin gagnaþjónusta fyrir farsíma"</string>
<string name="RestrictedOnEmergencyTitle" msgid="2852916906106191866">"Neyðarsímtöl eru ekki í boði"</string>
<string name="RestrictedOnNormalTitle" msgid="7009474589746551737">"Símtöl eru ekki í boði"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index b05bf79..b499eea 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -73,6 +73,10 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"ID chiamante generalmente non limitato. Prossima chiamata: non limitato"</string>
<string name="serviceNotProvisioned" msgid="8289333510236766193">"Servizio non fornito."</string>
<string name="CLIRPermanent" msgid="166443681876381118">"Non è possibile modificare l\'impostazione ID chiamante."</string>
+ <!-- no translation found for auto_data_switch_title (3286350716870518297) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_content (803557715007110959) -->
+ <skip />
<string name="RestrictedOnDataTitle" msgid="1500576417268169774">"Nessun servizio dati mobile"</string>
<string name="RestrictedOnEmergencyTitle" msgid="2852916906106191866">"Chiamate di emergenza non disponibili"</string>
<string name="RestrictedOnNormalTitle" msgid="7009474589746551737">"Nessun servizio di telefonia"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 8656fce..2ef4934 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -74,6 +74,8 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"זיהוי מתקשר עובר כברירת מחדל למצב לא מוגבל. השיחה הבאה: לא מוגבלת"</string>
<string name="serviceNotProvisioned" msgid="8289333510236766193">"השירות לא הוקצה."</string>
<string name="CLIRPermanent" msgid="166443681876381118">"אינך יכול לשנות את הגדרת זיהוי המתקשר."</string>
+ <string name="auto_data_switch_title" msgid="3286350716870518297">"הנתונים עברו אל <xliff:g id="CARRIERDISPLAY">%s</xliff:g>"</string>
+ <string name="auto_data_switch_content" msgid="803557715007110959">"תמיד אפשר לשנות זאת ב\'הגדרות\'"</string>
<string name="RestrictedOnDataTitle" msgid="1500576417268169774">"אין שירות של חבילת גלישה"</string>
<string name="RestrictedOnEmergencyTitle" msgid="2852916906106191866">"שיחות חירום לא זמינות"</string>
<string name="RestrictedOnNormalTitle" msgid="7009474589746551737">"אין אפשרות לבצע שיחות רגילות"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 69d0b9d..53fa057 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -72,6 +72,10 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"既定: 発信者番号通知、次の発信: 通知"</string>
<string name="serviceNotProvisioned" msgid="8289333510236766193">"提供可能なサービスがありません。"</string>
<string name="CLIRPermanent" msgid="166443681876381118">"発信者番号の設定は変更できません。"</string>
+ <!-- no translation found for auto_data_switch_title (3286350716870518297) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_content (803557715007110959) -->
+ <skip />
<string name="RestrictedOnDataTitle" msgid="1500576417268169774">"モバイルデータ サービスのブロック"</string>
<string name="RestrictedOnEmergencyTitle" msgid="2852916906106191866">"緊急通報のブロック"</string>
<string name="RestrictedOnNormalTitle" msgid="7009474589746551737">"音声通話サービス停止"</string>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index 6d32f25..57ff75a 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -72,6 +72,10 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"ნაგულისხმებად დაყენებულია ნომრის დაფარვის გამორთვა. შემდეგი ზარი: არ არის დაფარული."</string>
<string name="serviceNotProvisioned" msgid="8289333510236766193">"სერვისი არ არის მიწოდებული."</string>
<string name="CLIRPermanent" msgid="166443681876381118">"არ შეგიძლიათ აბონენტის ID პარამეტრების შეცვლა."</string>
+ <!-- no translation found for auto_data_switch_title (3286350716870518297) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_content (803557715007110959) -->
+ <skip />
<string name="RestrictedOnDataTitle" msgid="1500576417268169774">"მობილური ინტერნეტის სერვისი არ არის"</string>
<string name="RestrictedOnEmergencyTitle" msgid="2852916906106191866">"გადაუდებელი ზარი მიუწვდომელია"</string>
<string name="RestrictedOnNormalTitle" msgid="7009474589746551737">"ხმოვანი ზარების სერვისი არ არის"</string>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index 0d9fd3f..8f5b1c0 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -72,6 +72,10 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"Қоңырау шалушының жеке анықтағышы бастапқы бойынша шектелмеген. Келесі қоңырау: Шектелмеген"</string>
<string name="serviceNotProvisioned" msgid="8289333510236766193">"Қызмет ұсынылмаған."</string>
<string name="CLIRPermanent" msgid="166443681876381118">"Қоңырау шалушы идентификаторы параметрін өзгерту мүмкін емес."</string>
+ <!-- no translation found for auto_data_switch_title (3286350716870518297) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_content (803557715007110959) -->
+ <skip />
<string name="RestrictedOnDataTitle" msgid="1500576417268169774">"Мобильдік интернет қызметі жоқ"</string>
<string name="RestrictedOnEmergencyTitle" msgid="2852916906106191866">"Жедел қызметке қоңырау шалу қолжетімді емес"</string>
<string name="RestrictedOnNormalTitle" msgid="7009474589746551737">"Дауыстық қоңыраулар қызметі жоқ"</string>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index 0c82b66..1eae9db 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -72,6 +72,10 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"មិនបានដាក់កម្រិតលំនាំដើមលេខសម្គាល់អ្នកហៅ។ ការហៅបន្ទាប់៖ មិនបានដាក់កម្រិត។"</string>
<string name="serviceNotProvisioned" msgid="8289333510236766193">"មិនបានផ្ដល់សេវាកម្ម។"</string>
<string name="CLIRPermanent" msgid="166443681876381118">"អ្នកមិនអាចប្ដូរការកំណត់លេខសម្គាល់អ្នកហៅបានទេ។"</string>
+ <!-- no translation found for auto_data_switch_title (3286350716870518297) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_content (803557715007110959) -->
+ <skip />
<string name="RestrictedOnDataTitle" msgid="1500576417268169774">"គ្មានសេវាកម្មទិន្នន័យចល័តទេ"</string>
<string name="RestrictedOnEmergencyTitle" msgid="2852916906106191866">"ការហៅបន្ទាន់មិនអាចប្រើបានទេ"</string>
<string name="RestrictedOnNormalTitle" msgid="7009474589746551737">"គ្មានសេវាកម្មជាសំឡេងទេ"</string>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index e27527f..821138a 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -72,6 +72,10 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"ಕರೆಮಾಡುವವರ ID ಅನ್ನು ನಿರ್ಬಂಧಿಸದಿರುವಂತೆ ಡಿಫಾಲ್ಟ್ ಮಾಡಲಾಗಿದೆ. ಮುಂದಿನ ಕರೆ: ನಿರ್ಬಂಧಿಸಲಾಗಿಲ್ಲ"</string>
<string name="serviceNotProvisioned" msgid="8289333510236766193">"ಸೇವೆಯನ್ನು ಪೂರೈಸಲಾಗಿಲ್ಲ."</string>
<string name="CLIRPermanent" msgid="166443681876381118">"ನೀವು ಕಾಲರ್ ID ಸೆಟ್ಟಿಂಗ್ ಬದಲಾಯಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ."</string>
+ <!-- no translation found for auto_data_switch_title (3286350716870518297) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_content (803557715007110959) -->
+ <skip />
<string name="RestrictedOnDataTitle" msgid="1500576417268169774">"ಮೊಬೈಲ್ ಡೇಟಾ ಸೇವೆಯಿಲ್ಲ"</string>
<string name="RestrictedOnEmergencyTitle" msgid="2852916906106191866">"ತುರ್ತು ಕರೆ ಲಭ್ಯವಿಲ್ಲ"</string>
<string name="RestrictedOnNormalTitle" msgid="7009474589746551737">"ಧ್ವನಿ ಸೇವೆಯಿಲ್ಲ"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index c953a39..5f3c7ca 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -72,6 +72,10 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"발신자 번호가 기본적으로 제한되지 않음으로 설정됩니다. 다음 통화: 제한되지 않음"</string>
<string name="serviceNotProvisioned" msgid="8289333510236766193">"서비스가 준비되지 않았습니다."</string>
<string name="CLIRPermanent" msgid="166443681876381118">"발신자 번호 설정을 변경할 수 없습니다."</string>
+ <!-- no translation found for auto_data_switch_title (3286350716870518297) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_content (803557715007110959) -->
+ <skip />
<string name="RestrictedOnDataTitle" msgid="1500576417268169774">"모바일 데이터 서비스가 차단됨"</string>
<string name="RestrictedOnEmergencyTitle" msgid="2852916906106191866">"긴급 전화를 사용할 수 없음"</string>
<string name="RestrictedOnNormalTitle" msgid="7009474589746551737">"음성 서비스를 이용할 수 없음"</string>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index dccc4a6..6e7b355 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -72,6 +72,10 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"Номурду аныктоонун демейки абалы \"чектелбейт\" деп коюлган. Кийинки чалуу: Чектелбейт"</string>
<string name="serviceNotProvisioned" msgid="8289333510236766193">"Кызмат камсыздалган эмес."</string>
<string name="CLIRPermanent" msgid="166443681876381118">"Чалуучунун далдаштырма дайындары жөндөөлөрүн өзгөртө албайсыз."</string>
+ <!-- no translation found for auto_data_switch_title (3286350716870518297) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_content (803557715007110959) -->
+ <skip />
<string name="RestrictedOnDataTitle" msgid="1500576417268169774">"Мобилдик Интернет кызматы жок"</string>
<string name="RestrictedOnEmergencyTitle" msgid="2852916906106191866">"Шашылыш чалуу бөгөттөлгөн"</string>
<string name="RestrictedOnNormalTitle" msgid="7009474589746551737">"Аудио чалуу кызматы бөгөттөлгөн"</string>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index c6524de..7a76c2c 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -72,6 +72,10 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"ໝາຍເລກຜູ່ໂທ ໄດ້ຮັບການຕັ້ງຄ່າເລີ່ມຕົ້ນເປັນ ບໍ່ຖືກຈຳກັດ. ການໂທຄັ້ງຕໍ່ໄປ: ບໍ່ຖືກຈຳກັດ."</string>
<string name="serviceNotProvisioned" msgid="8289333510236766193">"ບໍ່ໄດ້ເປີດໃຊ້ບໍລິການ."</string>
<string name="CLIRPermanent" msgid="166443681876381118">"ທ່ານບໍ່ສາມາດປ່ຽນແປງການຕັ້ງຄ່າ Caller ID"</string>
+ <!-- no translation found for auto_data_switch_title (3286350716870518297) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_content (803557715007110959) -->
+ <skip />
<string name="RestrictedOnDataTitle" msgid="1500576417268169774">"ບໍ່ມີບໍລິການອິນເຕີເນັດມືຖື"</string>
<string name="RestrictedOnEmergencyTitle" msgid="2852916906106191866">"ບໍ່ສາມາດໃຊ້ການໂທສຸກເສີນໄດ້"</string>
<string name="RestrictedOnNormalTitle" msgid="7009474589746551737">"ບໍ່ມີບໍລິການໂທສຽງ"</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index adf30e8..e0d1fc7 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -74,6 +74,10 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"Skambintojo ID pagal numatytuosius nustatymus yra neapribotas. Kitas skambutis: neapribotas"</string>
<string name="serviceNotProvisioned" msgid="8289333510236766193">"Paslauga neteikiama."</string>
<string name="CLIRPermanent" msgid="166443681876381118">"Negalima pakeisti skambinančiojo ID nustatymo."</string>
+ <!-- no translation found for auto_data_switch_title (3286350716870518297) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_content (803557715007110959) -->
+ <skip />
<string name="RestrictedOnDataTitle" msgid="1500576417268169774">"Duomenų paslaugos mobiliesiems nėra"</string>
<string name="RestrictedOnEmergencyTitle" msgid="2852916906106191866">"Skambučių pagalbos numeriu paslaugos nėra"</string>
<string name="RestrictedOnNormalTitle" msgid="7009474589746551737">"Balso skambučių paslauga neteikiama"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 5631521..ec8cb7d 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -73,6 +73,10 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"Zvanītāja ID noklusējumi ir iestatīti uz Nav ierobežots. Nākamais zvans: nav ierobežots"</string>
<string name="serviceNotProvisioned" msgid="8289333510236766193">"Pakalpojums netiek nodrošināts."</string>
<string name="CLIRPermanent" msgid="166443681876381118">"Zvanītāja ID iestatījumu nevar mainīt."</string>
+ <!-- no translation found for auto_data_switch_title (3286350716870518297) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_content (803557715007110959) -->
+ <skip />
<string name="RestrictedOnDataTitle" msgid="1500576417268169774">"Nav pieejams neviens datu pakalpojums mobilajām ierīcēm"</string>
<string name="RestrictedOnEmergencyTitle" msgid="2852916906106191866">"Nav pieejami ārkārtas izsaukumi"</string>
<string name="RestrictedOnNormalTitle" msgid="7009474589746551737">"Balss izsaukumu pakalpojums nedarbojas"</string>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index a45d0a7..442047d 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -72,6 +72,10 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"Стандардно, ID на повикувач не е скриен. Следен повик: не е скриен"</string>
<string name="serviceNotProvisioned" msgid="8289333510236766193">"Услугата не е предвидена."</string>
<string name="CLIRPermanent" msgid="166443681876381118">"Не може да го промените поставувањето за ID на повикувач."</string>
+ <!-- no translation found for auto_data_switch_title (3286350716870518297) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_content (803557715007110959) -->
+ <skip />
<string name="RestrictedOnDataTitle" msgid="1500576417268169774">"Нема услуга за мобилен интернет"</string>
<string name="RestrictedOnEmergencyTitle" msgid="2852916906106191866">"Итните повици се недостапни"</string>
<string name="RestrictedOnNormalTitle" msgid="7009474589746551737">"Нема услуга за говорни повици"</string>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index 492cd54..5b59e66 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -72,6 +72,8 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"നിയന്ത്രിക്കേണ്ടതല്ലാത്ത സ്ഥിര കോളർ ഐഡികൾ. അടുത്ത കോൾ: നിയന്ത്രിച്ചിട്ടില്ല"</string>
<string name="serviceNotProvisioned" msgid="8289333510236766193">"സേവനം വ്യവസ്ഥ ചെയ്തിട്ടില്ല."</string>
<string name="CLIRPermanent" msgid="166443681876381118">"വിളിച്ച നമ്പർ ക്രമീകരണം നിങ്ങൾക്ക് മാറ്റാനാവില്ല."</string>
+ <string name="auto_data_switch_title" msgid="3286350716870518297">"<xliff:g id="CARRIERDISPLAY">%s</xliff:g> എന്നതിലേക്ക് ഡാറ്റ മാറ്റി"</string>
+ <string name="auto_data_switch_content" msgid="803557715007110959">"നിങ്ങൾക്ക് ക്രമീകരണത്തിൽ ഏതുസമയത്തും ഇത് മാറ്റാം"</string>
<string name="RestrictedOnDataTitle" msgid="1500576417268169774">"മൊബൈൽ ഡാറ്റാ സേവനമില്ല"</string>
<string name="RestrictedOnEmergencyTitle" msgid="2852916906106191866">"എമർജൻസി കോളിംഗ് ലഭ്യമല്ല"</string>
<string name="RestrictedOnNormalTitle" msgid="7009474589746551737">"വോയ്സ് സേവനമില്ല"</string>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index 2c8aaae..03deebb 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -72,6 +72,10 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"Дуудлага хийгчийн ID хязгаарлагдсан. Дараагийн дуудлага: Хязгаарлагдсан"</string>
<string name="serviceNotProvisioned" msgid="8289333510236766193">"Үйлчилгээ провишн хийгдээгүй ."</string>
<string name="CLIRPermanent" msgid="166443681876381118">"Та дуудлага хийгчийн ID тохиргоог солиж чадахгүй."</string>
+ <!-- no translation found for auto_data_switch_title (3286350716870518297) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_content (803557715007110959) -->
+ <skip />
<string name="RestrictedOnDataTitle" msgid="1500576417268169774">"Мобайл дата үйлчилгээ алга"</string>
<string name="RestrictedOnEmergencyTitle" msgid="2852916906106191866">"Яаралтай дуудлага боломжтой"</string>
<string name="RestrictedOnNormalTitle" msgid="7009474589746551737">"Дуу хоолойны үйлчилгээ алга"</string>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index d47fea35..1d25e67 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -72,6 +72,10 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"कॉलर आयडी डीफॉल्ट रूपात प्रतिबंधित नाही वर सेट असतो. पुढील कॉल: प्रतिबंधित नाही"</string>
<string name="serviceNotProvisioned" msgid="8289333510236766193">"सेवेची तरतूद केलेली नाही."</string>
<string name="CLIRPermanent" msgid="166443681876381118">"तुम्ही कॉलर आयडी सेटिंग बदलू शकत नाही."</string>
+ <!-- no translation found for auto_data_switch_title (3286350716870518297) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_content (803557715007110959) -->
+ <skip />
<string name="RestrictedOnDataTitle" msgid="1500576417268169774">"मोबाइल डेटा सेवा नाही"</string>
<string name="RestrictedOnEmergencyTitle" msgid="2852916906106191866">"आणीबाणी कॉलिंग अनुपलब्ध आहे"</string>
<string name="RestrictedOnNormalTitle" msgid="7009474589746551737">"व्हॉइस सेवा नाही"</string>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index deb343d..72d3f2f 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -72,6 +72,10 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"ID pemanggil secara lalainya ditetapkan kepada tidak dihadkan. Panggilan seterusnya: Tidak terhad"</string>
<string name="serviceNotProvisioned" msgid="8289333510236766193">"Perkhidmatan yang tidak diuntukkan."</string>
<string name="CLIRPermanent" msgid="166443681876381118">"Anda tidak boleh mengubah tetapan ID pemanggil."</string>
+ <!-- no translation found for auto_data_switch_title (3286350716870518297) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_content (803557715007110959) -->
+ <skip />
<string name="RestrictedOnDataTitle" msgid="1500576417268169774">"Tiada perkhidmatan data mudah alih"</string>
<string name="RestrictedOnEmergencyTitle" msgid="2852916906106191866">"Panggilan kecemasan tidak tersedia"</string>
<string name="RestrictedOnNormalTitle" msgid="7009474589746551737">"Tiada perkhidmatan suara"</string>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index 5f41672..5ff033d 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -72,6 +72,10 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"ပုံသေအားဖြင့် ခေါ်ဆိုသူအိုင်ဒီ(Caller ID)အား ကန့်သတ်မထားပါ။ နောက်ထပ်အဝင်ခေါ်ဆိုမှု-ကန့်သတ်မထားပါ။"</string>
<string name="serviceNotProvisioned" msgid="8289333510236766193">"ဝန်ဆောင်မှုအား ကန့်သတ်မထားပါ"</string>
<string name="CLIRPermanent" msgid="166443681876381118">"သင်သည် ခေါ်ဆိုသူ ID ဆက်တင်ကို မပြောင်းလဲနိုင်ပါ။"</string>
+ <!-- no translation found for auto_data_switch_title (3286350716870518297) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_content (803557715007110959) -->
+ <skip />
<string name="RestrictedOnDataTitle" msgid="1500576417268169774">"မိုဘိုင်း ဒေတာဝန်ဆောင်မှု မရှိပါ"</string>
<string name="RestrictedOnEmergencyTitle" msgid="2852916906106191866">"အရေးပေါ်ခေါ်ဆိုမှု မရနိုင်ပါ"</string>
<string name="RestrictedOnNormalTitle" msgid="7009474589746551737">"ဖုန်းဝန်ဆောင်မှု မရှိပါ"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 0c9a983..bb4fbe4 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -72,6 +72,10 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"Nummervisning er ikke begrenset som standard. Neste anrop: Ikke begrenset"</string>
<string name="serviceNotProvisioned" msgid="8289333510236766193">"SIM-kortet er ikke tilrettelagt for tjenesten."</string>
<string name="CLIRPermanent" msgid="166443681876381118">"Du kan ikke endre innstillingen for anrops-ID."</string>
+ <!-- no translation found for auto_data_switch_title (3286350716870518297) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_content (803557715007110959) -->
+ <skip />
<string name="RestrictedOnDataTitle" msgid="1500576417268169774">"Ingen mobildatatjeneste"</string>
<string name="RestrictedOnEmergencyTitle" msgid="2852916906106191866">"Nødanrop er utilgjengelig"</string>
<string name="RestrictedOnNormalTitle" msgid="7009474589746551737">"Ingen taletjeneste"</string>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index e95d48b..ea96df0 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -72,6 +72,10 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"कलर ID पूर्वनिर्धारितको लागि रोकावट छैन। अर्को कल: रोकावट छैन"</string>
<string name="serviceNotProvisioned" msgid="8289333510236766193">"सेवाको व्यवस्था छैन।"</string>
<string name="CLIRPermanent" msgid="166443681876381118">"तपाईं कलर ID सेटिङ परिवर्तन गर्न सक्नुहुन्न।"</string>
+ <!-- no translation found for auto_data_switch_title (3286350716870518297) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_content (803557715007110959) -->
+ <skip />
<string name="RestrictedOnDataTitle" msgid="1500576417268169774">"कुनै पनि मोबाइल डेटा सेवा उपलब्ध छैन"</string>
<string name="RestrictedOnEmergencyTitle" msgid="2852916906106191866">"आपत्कालीन कल सेवा उपलब्ध छैन"</string>
<string name="RestrictedOnNormalTitle" msgid="7009474589746551737">"कुनै पनि भ्वाइस सेवा उपलब्ध छैन"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 5723510..24877dd 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -72,6 +72,10 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"Beller-ID standaard ingesteld op \'onbeperkt\'. Volgend gesprek: onbeperkt."</string>
<string name="serviceNotProvisioned" msgid="8289333510236766193">"Service niet voorzien."</string>
<string name="CLIRPermanent" msgid="166443681876381118">"U kunt de instelling voor de beller-ID niet wijzigen."</string>
+ <!-- no translation found for auto_data_switch_title (3286350716870518297) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_content (803557715007110959) -->
+ <skip />
<string name="RestrictedOnDataTitle" msgid="1500576417268169774">"Geen service voor mobiele data"</string>
<string name="RestrictedOnEmergencyTitle" msgid="2852916906106191866">"Noodoproepen niet beschikbaar"</string>
<string name="RestrictedOnNormalTitle" msgid="7009474589746551737">"Geen belservice"</string>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index c4150dc..456fc83 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -72,6 +72,10 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"କଲର୍ ଆଇଡି ଡିଫଲ୍ଟ ଭାବରେ ପ୍ରତିବନ୍ଧିତ ନୁହେଁ। ପରବର୍ତ୍ତୀ କଲ୍: ପ୍ରତିବନ୍ଧିତ ନୁହେଁ"</string>
<string name="serviceNotProvisioned" msgid="8289333510236766193">"ସେବାର ସୁବିଧା ନାହିଁ।"</string>
<string name="CLIRPermanent" msgid="166443681876381118">"ଆପଣ କଲର୍ ID ସେଟିଙ୍ଗ ବଦଳାଇପାରିବେ ନାହିଁ।"</string>
+ <!-- no translation found for auto_data_switch_title (3286350716870518297) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_content (803557715007110959) -->
+ <skip />
<string name="RestrictedOnDataTitle" msgid="1500576417268169774">"କୌଣସି ମୋବାଇଲ୍ ଡାଟା ସେବା ନାହିଁ"</string>
<string name="RestrictedOnEmergencyTitle" msgid="2852916906106191866">"ଜରୁରୀକାଳୀନ କଲ୍ ଉପଲବ୍ଧ ନାହିଁ"</string>
<string name="RestrictedOnNormalTitle" msgid="7009474589746551737">"କୌଣସି ଭଏସ୍ ସେବା ନାହିଁ"</string>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index 96917c0..79ab897 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -72,6 +72,10 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"ਪ੍ਰਤਿਬੰਧਿਤ ਨਾ ਕਰਨ ਲਈ ਕਾਲਰ ਆਈ.ਡੀ. ਪੂਰਵ-ਨਿਰਧਾਰਤ। ਅਗਲੀ ਕਾਲ: ਪ੍ਰਤਿਬੰਧਿਤ ਨਹੀਂ"</string>
<string name="serviceNotProvisioned" msgid="8289333510236766193">"ਸੇਵਾ ਪ੍ਰਬੰਧਿਤ ਨਹੀਂ ਹੈ।"</string>
<string name="CLIRPermanent" msgid="166443681876381118">"ਤੁਸੀਂ ਕਾਲਰ ਆਈ.ਡੀ. ਸੈਟਿੰਗ ਨਹੀਂ ਬਦਲ ਸਕਦੇ।"</string>
+ <!-- no translation found for auto_data_switch_title (3286350716870518297) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_content (803557715007110959) -->
+ <skip />
<string name="RestrictedOnDataTitle" msgid="1500576417268169774">"ਕੋਈ ਮੋਬਾਈਲ ਡਾਟਾ ਸੇਵਾ ਨਹੀਂ"</string>
<string name="RestrictedOnEmergencyTitle" msgid="2852916906106191866">"ਸੰਕਟਕਾਲੀਨ ਕਾਲਿੰਗ ਉਪਲਬਧ ਨਹੀਂ"</string>
<string name="RestrictedOnNormalTitle" msgid="7009474589746551737">"ਕੋਈ ਆਵਾਜ਼ੀ ਸੇਵਾ ਨਹੀਂ"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index be9d322..5e3a64a 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -74,6 +74,10 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"ID rozmówcy ustawiony jest domyślnie na „nie zastrzeżony”. Następne połączenie: nie zastrzeżony"</string>
<string name="serviceNotProvisioned" msgid="8289333510236766193">"Usługa nie jest świadczona."</string>
<string name="CLIRPermanent" msgid="166443681876381118">"Nie możesz zmienić ustawienia ID rozmówcy."</string>
+ <!-- no translation found for auto_data_switch_title (3286350716870518297) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_content (803557715007110959) -->
+ <skip />
<string name="RestrictedOnDataTitle" msgid="1500576417268169774">"Brak komórkowej usługi transmisji danych"</string>
<string name="RestrictedOnEmergencyTitle" msgid="2852916906106191866">"Połączenia alarmowe są niedostępne"</string>
<string name="RestrictedOnNormalTitle" msgid="7009474589746551737">"Brak usługi połączeń głosowych"</string>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index ff352b1..34c0f0c 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -73,6 +73,10 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"O identificador de chamadas assume o padrão de não restrito. Próxima chamada: Não restrita"</string>
<string name="serviceNotProvisioned" msgid="8289333510236766193">"O serviço não foi habilitado."</string>
<string name="CLIRPermanent" msgid="166443681876381118">"Não é possível alterar a configuração do identificador de chamadas."</string>
+ <!-- no translation found for auto_data_switch_title (3286350716870518297) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_content (803557715007110959) -->
+ <skip />
<string name="RestrictedOnDataTitle" msgid="1500576417268169774">"Nenhum serviço móvel de dados"</string>
<string name="RestrictedOnEmergencyTitle" msgid="2852916906106191866">"Chamadas de emergência indisponíveis"</string>
<string name="RestrictedOnNormalTitle" msgid="7009474589746551737">"Sem serviço de voz"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index d343af6..0fb835b 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -73,6 +73,8 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"ID do autor da chamada é predefinido com não restrito. Chamada seguinte: Não restrita"</string>
<string name="serviceNotProvisioned" msgid="8289333510236766193">"Serviço não fornecido."</string>
<string name="CLIRPermanent" msgid="166443681876381118">"Não pode alterar a definição da identificação de chamadas."</string>
+ <string name="auto_data_switch_title" msgid="3286350716870518297">"Os dados móveis foram alterados para o operador <xliff:g id="CARRIERDISPLAY">%s</xliff:g>"</string>
+ <string name="auto_data_switch_content" msgid="803557715007110959">"Pode alterar isto em qualquer altura nas Definições"</string>
<string name="RestrictedOnDataTitle" msgid="1500576417268169774">"Sem serviço de dados móveis"</string>
<string name="RestrictedOnEmergencyTitle" msgid="2852916906106191866">"Chamadas de emergência indisponíveis"</string>
<string name="RestrictedOnNormalTitle" msgid="7009474589746551737">"Sem serviço de voz"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index ff352b1..34c0f0c 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -73,6 +73,10 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"O identificador de chamadas assume o padrão de não restrito. Próxima chamada: Não restrita"</string>
<string name="serviceNotProvisioned" msgid="8289333510236766193">"O serviço não foi habilitado."</string>
<string name="CLIRPermanent" msgid="166443681876381118">"Não é possível alterar a configuração do identificador de chamadas."</string>
+ <!-- no translation found for auto_data_switch_title (3286350716870518297) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_content (803557715007110959) -->
+ <skip />
<string name="RestrictedOnDataTitle" msgid="1500576417268169774">"Nenhum serviço móvel de dados"</string>
<string name="RestrictedOnEmergencyTitle" msgid="2852916906106191866">"Chamadas de emergência indisponíveis"</string>
<string name="RestrictedOnNormalTitle" msgid="7009474589746551737">"Sem serviço de voz"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index b560b07..88aab00 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -73,6 +73,10 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"ID-ul apelantului este nerestricționat în mod prestabilit. Apelul următor: nerestricționat"</string>
<string name="serviceNotProvisioned" msgid="8289333510236766193">"Nu se asigură accesul la acest serviciu."</string>
<string name="CLIRPermanent" msgid="166443681876381118">"Nu poți modifica setarea pentru ID-ul apelantului."</string>
+ <!-- no translation found for auto_data_switch_title (3286350716870518297) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_content (803557715007110959) -->
+ <skip />
<string name="RestrictedOnDataTitle" msgid="1500576417268169774">"Fără serviciu de date mobile"</string>
<string name="RestrictedOnEmergencyTitle" msgid="2852916906106191866">"Apelurile de urgență nu sunt disponibile"</string>
<string name="RestrictedOnNormalTitle" msgid="7009474589746551737">"Fără servicii vocale"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index fbe67e2..33bfe77 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -74,6 +74,10 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"Идентификация абонента по умолчанию не запрещена. След. вызов: разрешена"</string>
<string name="serviceNotProvisioned" msgid="8289333510236766193">"Услуга не предоставляется."</string>
<string name="CLIRPermanent" msgid="166443681876381118">"Невозможно изменить параметр идентификатора вызывающего абонента."</string>
+ <!-- no translation found for auto_data_switch_title (3286350716870518297) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_content (803557715007110959) -->
+ <skip />
<string name="RestrictedOnDataTitle" msgid="1500576417268169774">"Мобильный Интернет недоступен"</string>
<string name="RestrictedOnEmergencyTitle" msgid="2852916906106191866">"Экстренные вызовы недоступны"</string>
<string name="RestrictedOnNormalTitle" msgid="7009474589746551737">"Голосовые вызовы недоступны"</string>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index 4cec877..dd5b817 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -72,6 +72,10 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"අමතන්නාගේ ID සුපුරුදු අනුව සීමා වී නැත. මීළඟ ඇමතුම: සීමා කර ඇත"</string>
<string name="serviceNotProvisioned" msgid="8289333510236766193">"සේවාවන් සපයා නැත."</string>
<string name="CLIRPermanent" msgid="166443681876381118">"අමතන්නාගේ ID සැකසීම ඔබට වෙනස්කල නොහැක."</string>
+ <!-- no translation found for auto_data_switch_title (3286350716870518297) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_content (803557715007110959) -->
+ <skip />
<string name="RestrictedOnDataTitle" msgid="1500576417268169774">"ජංගම දත්ත සේවාව නැත"</string>
<string name="RestrictedOnEmergencyTitle" msgid="2852916906106191866">"හදිසි ඇමතුම් ලබා ගත නොහැකිය"</string>
<string name="RestrictedOnNormalTitle" msgid="7009474589746551737">"හඬ සේවාව නැත"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index b98364a..40abf79 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -74,6 +74,10 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"V predvolenom nastavení nie je identifikácia volajúceho obmedzená. Ďalší hovor: Bez obmedzenia"</string>
<string name="serviceNotProvisioned" msgid="8289333510236766193">"Služba nie je poskytovaná."</string>
<string name="CLIRPermanent" msgid="166443681876381118">"Nemôžete meniť nastavenie identifikácie volajúcich."</string>
+ <!-- no translation found for auto_data_switch_title (3286350716870518297) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_content (803557715007110959) -->
+ <skip />
<string name="RestrictedOnDataTitle" msgid="1500576417268169774">"Žiadna mobilná dátová služba"</string>
<string name="RestrictedOnEmergencyTitle" msgid="2852916906106191866">"Tiesňové volania nie sú k dispozícii"</string>
<string name="RestrictedOnNormalTitle" msgid="7009474589746551737">"Žiadne hlasové hovory"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 6972abb..53a0321 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -74,6 +74,10 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"ID klicatelja je ponastavljen na neomejeno. Naslednji klic: ni omejeno"</string>
<string name="serviceNotProvisioned" msgid="8289333510236766193">"Storitev ni nastavljena in omogočena."</string>
<string name="CLIRPermanent" msgid="166443681876381118">"Ne morete spremeniti nastavitve ID-ja klicatelja."</string>
+ <!-- no translation found for auto_data_switch_title (3286350716870518297) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_content (803557715007110959) -->
+ <skip />
<string name="RestrictedOnDataTitle" msgid="1500576417268169774">"Ni mobilne podatkovne storitve"</string>
<string name="RestrictedOnEmergencyTitle" msgid="2852916906106191866">"Klicanje v sili ni na voljo"</string>
<string name="RestrictedOnNormalTitle" msgid="7009474589746551737">"Ni storitve za glasovne klice"</string>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index cbac0f0..6c3f145 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -72,6 +72,10 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"ID-ja e telefonuesit kalon me paracaktim në listën e të telefonuesve të pakufizuar. Telefonata e radhës: e pakufizuar!"</string>
<string name="serviceNotProvisioned" msgid="8289333510236766193">"Shërbimi nuk është përgatitur."</string>
<string name="CLIRPermanent" msgid="166443681876381118">"Nuk mund ta ndryshosh cilësimin e ID-së së telefonuesit."</string>
+ <!-- no translation found for auto_data_switch_title (3286350716870518297) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_content (803557715007110959) -->
+ <skip />
<string name="RestrictedOnDataTitle" msgid="1500576417268169774">"Nuk ka shërbim të të dhënave celulare"</string>
<string name="RestrictedOnEmergencyTitle" msgid="2852916906106191866">"Telefonatat e urgjencës nuk ofrohen"</string>
<string name="RestrictedOnNormalTitle" msgid="7009474589746551737">"Nuk ka shërbim zanor"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index d5549e7..d23b056 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -73,6 +73,10 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"ИД позиваоца подразумевано није ограничен. Следећи позив: Није ограничен."</string>
<string name="serviceNotProvisioned" msgid="8289333510236766193">"Услуга није добављена."</string>
<string name="CLIRPermanent" msgid="166443681876381118">"Не можете да промените подешавање ИД-а корисника."</string>
+ <!-- no translation found for auto_data_switch_title (3286350716870518297) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_content (803557715007110959) -->
+ <skip />
<string name="RestrictedOnDataTitle" msgid="1500576417268169774">"Нема услуге мобилних података"</string>
<string name="RestrictedOnEmergencyTitle" msgid="2852916906106191866">"Хитни позиви нису доступни"</string>
<string name="RestrictedOnNormalTitle" msgid="7009474589746551737">"Нема гласовне услуге"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index d1c579d..ee6a8ac 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -72,6 +72,10 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"Nummerpresentatörens standardinställning är inte blockerad. Nästa samtal: Inte blockerad"</string>
<string name="serviceNotProvisioned" msgid="8289333510236766193">"Tjänsten är inte etablerad."</string>
<string name="CLIRPermanent" msgid="166443681876381118">"Det går inte att ändra inställningen för nummerpresentatör."</string>
+ <!-- no translation found for auto_data_switch_title (3286350716870518297) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_content (803557715007110959) -->
+ <skip />
<string name="RestrictedOnDataTitle" msgid="1500576417268169774">"Ingen mobildatatjänst"</string>
<string name="RestrictedOnEmergencyTitle" msgid="2852916906106191866">"Det går inte att ringa nödsamtal"</string>
<string name="RestrictedOnNormalTitle" msgid="7009474589746551737">"Tjänsten för röstsamtal har blockerats"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 2bc3f57..7b9d89f 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -72,6 +72,10 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"Chaguomsingi za ID ya mpigaji simu za kutozuia. Simu ifuatayo: Haijazuiliwa"</string>
<string name="serviceNotProvisioned" msgid="8289333510236766193">"Huduma haitathminiwi."</string>
<string name="CLIRPermanent" msgid="166443681876381118">"Hauwezi kubadilisha mpangilio wa kitambulisho cha anayepiga."</string>
+ <!-- no translation found for auto_data_switch_title (3286350716870518297) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_content (803557715007110959) -->
+ <skip />
<string name="RestrictedOnDataTitle" msgid="1500576417268169774">"Hakuna huduma ya data kwa vifaa vya mkononi"</string>
<string name="RestrictedOnEmergencyTitle" msgid="2852916906106191866">"Huduma ya kupiga simu za dharura haipatikani"</string>
<string name="RestrictedOnNormalTitle" msgid="7009474589746551737">"Hakuna huduma za simu za sauti"</string>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index 9e48a47..2a0fc2c 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -72,6 +72,10 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"அழைப்பாளர் ஐடி ஆனது வரையறுக்கப்படவில்லை என்பதற்கு இயல்பாக அமைக்கப்பட்டது. அடுத்த அழைப்பு: வரையறுக்கப்படவில்லை"</string>
<string name="serviceNotProvisioned" msgid="8289333510236766193">"சேவை ஒதுக்கப்படவில்லை."</string>
<string name="CLIRPermanent" msgid="166443681876381118">"அழைப்பாளர் ஐடி அமைப்பை மாற்ற முடியாது."</string>
+ <!-- no translation found for auto_data_switch_title (3286350716870518297) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_content (803557715007110959) -->
+ <skip />
<string name="RestrictedOnDataTitle" msgid="1500576417268169774">"மொபைல் டேட்டா சேவையைப் பயன்படுத்த முடியாது"</string>
<string name="RestrictedOnEmergencyTitle" msgid="2852916906106191866">"அவசர அழைப்பைச் செய்ய முடியாது"</string>
<string name="RestrictedOnNormalTitle" msgid="7009474589746551737">"குரல் சேவை இல்லை"</string>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index eff08bc..a7c2d4e 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -72,6 +72,10 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"కాలర్ ID ఆటోమేటిక్లపై పరిమితి లేదు. తర్వాత కాల్: పరిమితి లేదు"</string>
<string name="serviceNotProvisioned" msgid="8289333510236766193">"సేవ కేటాయించబడలేదు."</string>
<string name="CLIRPermanent" msgid="166443681876381118">"మీరు కాలర్ ID సెట్టింగ్ను మార్చలేరు."</string>
+ <!-- no translation found for auto_data_switch_title (3286350716870518297) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_content (803557715007110959) -->
+ <skip />
<string name="RestrictedOnDataTitle" msgid="1500576417268169774">"మొబైల్ డేటా సేవ లేదు"</string>
<string name="RestrictedOnEmergencyTitle" msgid="2852916906106191866">"అత్యవసర కాలింగ్ అందుబాటులో లేదు"</string>
<string name="RestrictedOnNormalTitle" msgid="7009474589746551737">"వాయిస్ సర్వీస్ లేదు"</string>
@@ -2071,7 +2075,7 @@
<string name="notification_appops_camera_active" msgid="8177643089272352083">"కెమెరా"</string>
<string name="notification_appops_microphone_active" msgid="581333393214739332">"మైక్రోఫోన్"</string>
<string name="notification_appops_overlay_active" msgid="5571732753262836481">"మీ స్క్రీన్పై ఇతర యాప్ల ద్వారా ప్రదర్శించబడుతోంది"</string>
- <string name="notification_feedback_indicator" msgid="663476517711323016">"ఫీడ్బ్యాక్ను అందించండి"</string>
+ <string name="notification_feedback_indicator" msgid="663476517711323016">"ఫీడ్బ్యాక్ ఇవ్వండి"</string>
<string name="notification_feedback_indicator_alerted" msgid="6552871804121942099">"ఈ నోటిఫికేషన్, ఆటోమేటిక్ సెట్టింగ్కు ప్రమోట్ చేయబడింది. ఫీడ్బ్యాక్ను అందించడానికి ట్యాప్ చేయండి."</string>
<string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"ఈ నోటిఫికేషన్ స్థాయి నిశ్శబ్దంగా ఉండేలా తగ్గించబడింది. ఫీడ్బ్యాక్ను అందించడానికి ట్యాప్ చేయండి."</string>
<string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"ఈ నోటిఫికేషన్కు ఎక్కువ ర్యాంక్ ఇవ్వబడింది. ఫీడ్బ్యాక్ను అందించడానికి ట్యాప్ చేయండి."</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 72cbc36..c0ab275 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -72,6 +72,8 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"หมายเลขผู้โทรได้รับการตั้งค่าเริ่มต้นเป็นไม่จำกัด การโทรครั้งต่อไป: ไม่จำกัด"</string>
<string name="serviceNotProvisioned" msgid="8289333510236766193">"ไม่มีการนำเสนอบริการ"</string>
<string name="CLIRPermanent" msgid="166443681876381118">"คุณไม่สามารถเปลี่ยนการตั้งค่าหมายเลขผู้โทร"</string>
+ <string name="auto_data_switch_title" msgid="3286350716870518297">"เปลี่ยนไปใช้อินเทอร์เน็ตมือถือของ <xliff:g id="CARRIERDISPLAY">%s</xliff:g> แล้ว"</string>
+ <string name="auto_data_switch_content" msgid="803557715007110959">"คุณเปลี่ยนตัวเลือกนี้ได้ทุกเมื่อในการตั้งค่า"</string>
<string name="RestrictedOnDataTitle" msgid="1500576417268169774">"ไม่มีบริการเน็ตมือถือ"</string>
<string name="RestrictedOnEmergencyTitle" msgid="2852916906106191866">"หมายเลขฉุกเฉินไม่พร้อมใช้งาน"</string>
<string name="RestrictedOnNormalTitle" msgid="7009474589746551737">"ไม่มีบริการเสียง"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index e66999d..7b9807a 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -72,6 +72,8 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"Naka-default na hindi pinaghihigpitan ang Caller ID. Susunod na tawag: Hindi pinaghihigpitan"</string>
<string name="serviceNotProvisioned" msgid="8289333510236766193">"Hindi naprobisyon ang serbisyo."</string>
<string name="CLIRPermanent" msgid="166443681876381118">"Hindi mo mababago ang setting ng caller ID."</string>
+ <string name="auto_data_switch_title" msgid="3286350716870518297">"Nailipat sa <xliff:g id="CARRIERDISPLAY">%s</xliff:g> ang data"</string>
+ <string name="auto_data_switch_content" msgid="803557715007110959">"Puwede mo itong baguhin anumang oras sa Mga Setting"</string>
<string name="RestrictedOnDataTitle" msgid="1500576417268169774">"Walang serbisyo ng data sa mobile"</string>
<string name="RestrictedOnEmergencyTitle" msgid="2852916906106191866">"Hindi available ang pang-emergency na pagtawag"</string>
<string name="RestrictedOnNormalTitle" msgid="7009474589746551737">"Walang serbisyo para sa boses"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index b6c4b4a..3459cb0 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -72,6 +72,10 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"Arayan kimliği varsayılanları kısıtlanmamıştır. Sonraki çağrı: Kısıtlanmamış"</string>
<string name="serviceNotProvisioned" msgid="8289333510236766193">"Hizmet sağlanamadı."</string>
<string name="CLIRPermanent" msgid="166443681876381118">"Arayanın kimliği ayarını değiştiremezsiniz."</string>
+ <!-- no translation found for auto_data_switch_title (3286350716870518297) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_content (803557715007110959) -->
+ <skip />
<string name="RestrictedOnDataTitle" msgid="1500576417268169774">"Mobil veri hizmeti yok"</string>
<string name="RestrictedOnEmergencyTitle" msgid="2852916906106191866">"Acil durum çağrısı kullanılamaz"</string>
<string name="RestrictedOnNormalTitle" msgid="7009474589746551737">"Sesli çağrı hizmeti yok"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index c408c51..2483a30 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -74,6 +74,10 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"Ідентиф. абонента за умовч. не обмеж. Наст. дзвінок: не обмежений"</string>
<string name="serviceNotProvisioned" msgid="8289333510236766193">"Службу не ініціалізовано."</string>
<string name="CLIRPermanent" msgid="166443681876381118">"Ви не можете змінювати налаштування ідентифікатора абонента."</string>
+ <!-- no translation found for auto_data_switch_title (3286350716870518297) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_content (803557715007110959) -->
+ <skip />
<string name="RestrictedOnDataTitle" msgid="1500576417268169774">"Службу передавання мобільних даних заблоковано"</string>
<string name="RestrictedOnEmergencyTitle" msgid="2852916906106191866">"Екстрені виклики недоступні"</string>
<string name="RestrictedOnNormalTitle" msgid="7009474589746551737">"Немає голосової служби"</string>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index 7784431..7de793c 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -72,6 +72,10 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"کالر ID کی ڈیفالٹ ترتیب غیر محدود کردہ ہے۔ اگلی کال: غیر محدود کردہ"</string>
<string name="serviceNotProvisioned" msgid="8289333510236766193">"سروس فراہم نہیں کی گئی۔"</string>
<string name="CLIRPermanent" msgid="166443681876381118">"آپ کالر ID کی ترتیبات تبدیل نہیں کر سکتے ہیں۔"</string>
+ <!-- no translation found for auto_data_switch_title (3286350716870518297) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_content (803557715007110959) -->
+ <skip />
<string name="RestrictedOnDataTitle" msgid="1500576417268169774">"کوئی موبائل ڈیٹا سروس دستیاب نہیں ہے"</string>
<string name="RestrictedOnEmergencyTitle" msgid="2852916906106191866">"ہنگامی کالنگ دستیاب نہیں ہے"</string>
<string name="RestrictedOnNormalTitle" msgid="7009474589746551737">"کوئی صوتی سروس نہیں"</string>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index 5ac689d1..8c88585 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -72,6 +72,10 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"Qo‘ng‘iroq qiluvchi ma’lumotlari cheklanmagan. Keyingi qo‘ng‘iroq: cheklanmagan"</string>
<string name="serviceNotProvisioned" msgid="8289333510236766193">"Xizmat ishalamaydi."</string>
<string name="CLIRPermanent" msgid="166443681876381118">"Qo‘ng‘iroq qiluvchining ID raqami sozlamasini o‘zgartirib bo‘lmaydi."</string>
+ <!-- no translation found for auto_data_switch_title (3286350716870518297) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_content (803557715007110959) -->
+ <skip />
<string name="RestrictedOnDataTitle" msgid="1500576417268169774">"Mobil internet ishlamayapti"</string>
<string name="RestrictedOnEmergencyTitle" msgid="2852916906106191866">"Favqulodda chaqiruv ishlamayapti"</string>
<string name="RestrictedOnNormalTitle" msgid="7009474589746551737">"Ovozli chaqiruvlar ishlamaydi"</string>
@@ -1592,7 +1596,7 @@
<string name="issued_by" msgid="7872459822431585684">"Tegishli:"</string>
<string name="validity_period" msgid="1717724283033175968">"Yaroqliligi:"</string>
<string name="issued_on" msgid="5855489688152497307">"Chiqarilgan sanasi:"</string>
- <string name="expires_on" msgid="1623640879705103121">"Amal qilish muddati:"</string>
+ <string name="expires_on" msgid="1623640879705103121">"Muddati:"</string>
<string name="serial_number" msgid="3479576915806623429">"Serial raqam:"</string>
<string name="fingerprints" msgid="148690767172613723">"Barmoq izlari:"</string>
<string name="sha256_fingerprint" msgid="7103976380961964600">"SHA-256 barmoq izi:"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index e1b479c..68bb062 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -72,6 +72,10 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"Số gọi đến mặc định thành không bị giới hạn. Cuộc gọi tiếp theo. Không bị giới hạn"</string>
<string name="serviceNotProvisioned" msgid="8289333510236766193">"Dịch vụ không được cấp phép."</string>
<string name="CLIRPermanent" msgid="166443681876381118">"Bạn không thể thay đổi cài đặt ID người gọi."</string>
+ <!-- no translation found for auto_data_switch_title (3286350716870518297) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_content (803557715007110959) -->
+ <skip />
<string name="RestrictedOnDataTitle" msgid="1500576417268169774">"Không có dịch vụ dữ liệu di động"</string>
<string name="RestrictedOnEmergencyTitle" msgid="2852916906106191866">"Không có dịch vụ gọi khẩn cấp"</string>
<string name="RestrictedOnNormalTitle" msgid="7009474589746551737">"Không có dịch vụ thoại"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 5fce25e..f2b033e 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -72,6 +72,10 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"默认显示本机号码,在下一次通话中也显示"</string>
<string name="serviceNotProvisioned" msgid="8289333510236766193">"未提供服务。"</string>
<string name="CLIRPermanent" msgid="166443681876381118">"您无法更改来电显示设置。"</string>
+ <!-- no translation found for auto_data_switch_title (3286350716870518297) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_content (803557715007110959) -->
+ <skip />
<string name="RestrictedOnDataTitle" msgid="1500576417268169774">"无法使用移动数据服务"</string>
<string name="RestrictedOnEmergencyTitle" msgid="2852916906106191866">"无法使用紧急呼救服务"</string>
<string name="RestrictedOnNormalTitle" msgid="7009474589746551737">"无法使用语音通话服务"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index 61a3f20..63995bb 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -72,6 +72,10 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"預設顯示來電號碼,下一通電話也繼續顯示。"</string>
<string name="serviceNotProvisioned" msgid="8289333510236766193">"未提供此服務。"</string>
<string name="CLIRPermanent" msgid="166443681876381118">"您無法更改來電顯示設定。"</string>
+ <!-- no translation found for auto_data_switch_title (3286350716870518297) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_content (803557715007110959) -->
+ <skip />
<string name="RestrictedOnDataTitle" msgid="1500576417268169774">"無法使用流動數據服務"</string>
<string name="RestrictedOnEmergencyTitle" msgid="2852916906106191866">"無法撥打緊急電話"</string>
<string name="RestrictedOnNormalTitle" msgid="7009474589746551737">"沒有語音服務"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 10dc699..55f9321 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -72,6 +72,10 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"預設顯示本機號碼,下一通電話也繼續顯示。"</string>
<string name="serviceNotProvisioned" msgid="8289333510236766193">"無法提供此服務。"</string>
<string name="CLIRPermanent" msgid="166443681876381118">"你無法變更來電顯示設定。"</string>
+ <!-- no translation found for auto_data_switch_title (3286350716870518297) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_content (803557715007110959) -->
+ <skip />
<string name="RestrictedOnDataTitle" msgid="1500576417268169774">"沒有行動數據傳輸服務"</string>
<string name="RestrictedOnEmergencyTitle" msgid="2852916906106191866">"無法撥打緊急電話"</string>
<string name="RestrictedOnNormalTitle" msgid="7009474589746551737">"無法使用語音通話服務"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 66d639e..2218b76 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -72,6 +72,10 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"I-ID Yomshayeli ishintshela kokungavinjelwe. Ucingo olulandelayo: Aluvinjelwe"</string>
<string name="serviceNotProvisioned" msgid="8289333510236766193">"Isevisi ayilungiselelwe."</string>
<string name="CLIRPermanent" msgid="166443681876381118">"Ngeke ukwazi ukuguqul izilungiselelo zemininingwane yoshayayo."</string>
+ <!-- no translation found for auto_data_switch_title (3286350716870518297) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_content (803557715007110959) -->
+ <skip />
<string name="RestrictedOnDataTitle" msgid="1500576417268169774">"Ayikho isevisi yedatha yeselula"</string>
<string name="RestrictedOnEmergencyTitle" msgid="2852916906106191866">"Ukushaya okuphuthumayo akutholakali"</string>
<string name="RestrictedOnNormalTitle" msgid="7009474589746551737">"Ayikho isevisi yezwi"</string>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 23dd1b4..a1f46fc 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -4425,13 +4425,13 @@
<string name="config_mediaProjectionPermissionDialogComponent" translatable="false">com.android.systemui/com.android.systemui.media.MediaProjectionPermissionActivity</string>
<!-- Corner radius of system dialogs -->
- <dimen name="config_dialogCornerRadius">2dp</dimen>
+ <dimen name="config_dialogCornerRadius">28dp</dimen>
<!-- Corner radius of system buttons -->
- <dimen name="config_buttonCornerRadius">@dimen/control_corner_material</dimen>
+ <dimen name="config_buttonCornerRadius">4dp</dimen>
<!-- Corner radius for bottom sheet system dialogs -->
- <dimen name="config_bottomDialogCornerRadius">@dimen/config_dialogCornerRadius</dimen>
+ <dimen name="config_bottomDialogCornerRadius">16dp</dimen>
<!-- Corner radius of system progress bars -->
- <dimen name="config_progressBarCornerRadius">@dimen/progress_bar_corner_material</dimen>
+ <dimen name="config_progressBarCornerRadius">1000dp</dimen>
<!-- Controls whether system buttons use all caps for text -->
<bool name="config_buttonTextAllCaps">true</bool>
<!-- Name of the font family used for system surfaces where the font should use medium weight -->
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 1997261..9dbb6a0 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -979,9 +979,9 @@
<dimen name="controls_thumbnail_image_max_width">280dp</dimen>
<!-- System-provided radius for the background view of app widgets. The resolved value of this resource may change at runtime. -->
- <dimen name="system_app_widget_background_radius">16dp</dimen>
+ <dimen name="system_app_widget_background_radius">28dp</dimen>
<!-- System-provided radius for inner views on app widgets. The resolved value of this resource may change at runtime. -->
- <dimen name="system_app_widget_inner_radius">8dp</dimen>
+ <dimen name="system_app_widget_inner_radius">20dp</dimen>
<!-- System-provided padding for inner views on app widgets. The resolved value of this resource may change at runtime. @removed -->
<dimen name="__removed_system_app_widget_internal_padding">16dp</dimen>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 509de33..1f459c6 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1933,6 +1933,11 @@
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. "shared storage" refers to a storage space on the device that all apps with this permission can read from. [CHAR LIMIT=none] -->
<string name="permdesc_readMediaImages">Allows the app to read image files from your shared storage.</string>
+ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. "shared storage" refers to a storage space on the device that all apps with this permission can read from. [CHAR LIMIT=none] -->
+ <string name="permlab_readVisualUserSelect">read user selected image and video files from shared storage</string>
+ <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. "shared storage" refers to a storage space on the device that all apps with this permission can read from. [CHAR LIMIT=none] -->
+ <string name="permdesc_readVisualUserSelect">Allows the app to read image and video files that you select from your shared storage.</string>
+
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. "shared storage" refers to a storage space on the device that all apps with this permission can write to. [CHAR LIMIT=none] -->
<string name="permlab_sdcardWrite">modify or delete the contents of your shared storage</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. "shared storage" refers to a storage space on the device that all apps with this permission can write to. [CHAR LIMIT=none] -->
diff --git a/core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/unittests/ProgramSelectorTest.java b/core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/unittests/ProgramSelectorTest.java
index 57b9cb1..5bd018b 100644
--- a/core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/unittests/ProgramSelectorTest.java
+++ b/core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/unittests/ProgramSelectorTest.java
@@ -23,11 +23,13 @@
import android.annotation.Nullable;
import android.hardware.radio.ProgramSelector;
import android.hardware.radio.RadioManager;
+import android.os.Parcel;
import org.junit.Test;
public final class ProgramSelectorTest {
+ private static final int CREATOR_ARRAY_SIZE = 2;
private static final int FM_PROGRAM_TYPE = ProgramSelector.PROGRAM_TYPE_FM;
private static final int DAB_PROGRAM_TYPE = ProgramSelector.PROGRAM_TYPE_DAB;
private static final long FM_FREQUENCY = 88500;
@@ -97,6 +99,33 @@
}
@Test
+ public void describeContents_forIdentifier() {
+ assertWithMessage("FM identifier contents")
+ .that(FM_IDENTIFIER.describeContents()).isEqualTo(0);
+ }
+
+ @Test
+ public void newArray_forIdentifierCreator() {
+ ProgramSelector.Identifier[] identifiers =
+ ProgramSelector.Identifier.CREATOR.newArray(CREATOR_ARRAY_SIZE);
+
+ assertWithMessage("Identifiers").that(identifiers).hasLength(CREATOR_ARRAY_SIZE);
+ }
+
+ @Test
+ public void writeToParcel_forIdentifier() {
+ Parcel parcel = Parcel.obtain();
+
+ FM_IDENTIFIER.writeToParcel(parcel, /* flags= */ 0);
+ parcel.setDataPosition(0);
+
+ ProgramSelector.Identifier identifierFromParcel =
+ ProgramSelector.Identifier.CREATOR.createFromParcel(parcel);
+ assertWithMessage("Identifier created from parcel")
+ .that(identifierFromParcel).isEqualTo(FM_IDENTIFIER);
+ }
+
+ @Test
public void getProgramType() {
ProgramSelector selector = getFmSelector(/* secondaryIds= */ null, /* vendorIds= */ null);
@@ -394,6 +423,34 @@
.that(selector1.strictEquals(selector2)).isTrue();
}
+ @Test
+ public void describeContents_forProgramSelector() {
+ assertWithMessage("FM selector contents")
+ .that(getFmSelector(/* secondaryIds= */ null, /* vendorIds= */ null)
+ .describeContents()).isEqualTo(0);
+ }
+
+ @Test
+ public void newArray_forProgramSelectorCreator() {
+ ProgramSelector[] programSelectors = ProgramSelector.CREATOR.newArray(CREATOR_ARRAY_SIZE);
+
+ assertWithMessage("Program selectors").that(programSelectors).hasLength(CREATOR_ARRAY_SIZE);
+ }
+
+ @Test
+ public void writeToParcel_forProgramSelector() {
+ ProgramSelector selectorExpected =
+ getFmSelector(/* secondaryIds= */ null, /* vendorIds= */ null);
+ Parcel parcel = Parcel.obtain();
+
+ selectorExpected.writeToParcel(parcel, /* flags= */ 0);
+ parcel.setDataPosition(0);
+
+ ProgramSelector selectorFromParcel = ProgramSelector.CREATOR.createFromParcel(parcel);
+ assertWithMessage("Program selector created from parcel")
+ .that(selectorFromParcel).isEqualTo(selectorExpected);
+ }
+
private ProgramSelector getFmSelector(@Nullable ProgramSelector.Identifier[] secondaryIds,
@Nullable long[] vendorIds) {
return new ProgramSelector(FM_PROGRAM_TYPE, FM_IDENTIFIER, secondaryIds, vendorIds);
diff --git a/core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/unittests/RadioAnnouncementTest.java b/core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/unittests/RadioAnnouncementTest.java
index 42143b9..6e1bb4b4 100644
--- a/core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/unittests/RadioAnnouncementTest.java
+++ b/core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/unittests/RadioAnnouncementTest.java
@@ -22,6 +22,7 @@
import android.hardware.radio.Announcement;
import android.hardware.radio.ProgramSelector;
+import android.os.Parcel;
import android.util.ArrayMap;
import org.junit.Test;
@@ -83,4 +84,35 @@
vendorInfo.put("vendorKeyMock", "vendorValueMock");
return vendorInfo;
}
+
+ @Test
+ public void describeContents_forAnnouncement() {
+ assertWithMessage("Radio announcement contents")
+ .that(TEST_ANNOUNCEMENT.describeContents()).isEqualTo(0);
+ }
+
+ @Test
+ public void newArray_forAnnouncementCreator() {
+ int sizeExpected = 2;
+
+ Announcement[] announcements = Announcement.CREATOR.newArray(sizeExpected);
+
+ assertWithMessage("Announcements").that(announcements).hasLength(sizeExpected);
+ }
+
+ @Test
+ public void writeToParcel_forAnnouncement() {
+ Parcel parcel = Parcel.obtain();
+
+ TEST_ANNOUNCEMENT.writeToParcel(parcel, /* flags= */ 0);
+ parcel.setDataPosition(0);
+
+ Announcement announcementFromParcel = Announcement.CREATOR.createFromParcel(parcel);
+ assertWithMessage("Selector of announcement created from parcel")
+ .that(announcementFromParcel.getSelector()).isEqualTo(FM_PROGRAM_SELECTOR);
+ assertWithMessage("Type of announcement created from parcel")
+ .that(announcementFromParcel.getType()).isEqualTo(TRAFFIC_ANNOUNCEMENT_TYPE);
+ assertWithMessage("Vendor info of announcement created from parcel")
+ .that(announcementFromParcel.getVendorInfo()).isEqualTo(VENDOR_INFO);
+ }
}
diff --git a/core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/unittests/RadioManagerTest.java b/core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/unittests/RadioManagerTest.java
index be4d0d4..f838a5d 100644
--- a/core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/unittests/RadioManagerTest.java
+++ b/core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/unittests/RadioManagerTest.java
@@ -33,6 +33,7 @@
import android.hardware.radio.RadioManager;
import android.hardware.radio.RadioMetadata;
import android.hardware.radio.RadioTuner;
+import android.os.Parcel;
import android.os.RemoteException;
import android.util.ArrayMap;
@@ -80,6 +81,8 @@
private static final int[] SUPPORTED_IDENTIFIERS_TYPES = new int[]{
ProgramSelector.IDENTIFIER_TYPE_AMFM_FREQUENCY, ProgramSelector.IDENTIFIER_TYPE_RDS_PI};
+ private static final int CREATOR_ARRAY_SIZE = 3;
+
private static final RadioManager.FmBandDescriptor FM_BAND_DESCRIPTOR =
createFmBandDescriptor();
private static final RadioManager.AmBandDescriptor AM_BAND_DESCRIPTOR =
@@ -173,6 +176,22 @@
}
@Test
+ public void describeContents_forBandDescriptor() {
+ RadioManager.BandDescriptor bandDescriptor = createFmBandDescriptor();
+
+ assertWithMessage("Band Descriptor contents")
+ .that(bandDescriptor.describeContents()).isEqualTo(0);
+ }
+
+ @Test
+ public void newArray_forBandDescriptorCreator() {
+ RadioManager.BandDescriptor[] bandDescriptors =
+ RadioManager.BandDescriptor.CREATOR.newArray(CREATOR_ARRAY_SIZE);
+
+ assertWithMessage("Band Descriptors").that(bandDescriptors).hasLength(CREATOR_ARRAY_SIZE);
+ }
+
+ @Test
public void isAmBand_forAmBandDescriptor_returnsTrue() {
RadioManager.BandDescriptor bandDescriptor = createAmBandDescriptor();
@@ -219,18 +238,73 @@
}
@Test
+ public void describeContents_forFmBandDescriptor() {
+ assertWithMessage("FM Band Descriptor contents")
+ .that(FM_BAND_DESCRIPTOR.describeContents()).isEqualTo(0);
+ }
+
+ @Test
+ public void writeToParcel_forFmBandDescriptor() {
+ Parcel parcel = Parcel.obtain();
+
+ FM_BAND_DESCRIPTOR.writeToParcel(parcel, /* flags= */ 0);
+ parcel.setDataPosition(0);
+
+ RadioManager.FmBandDescriptor fmBandDescriptorFromParcel =
+ RadioManager.FmBandDescriptor.CREATOR.createFromParcel(parcel);
+ assertWithMessage("FM Band Descriptor created from parcel")
+ .that(fmBandDescriptorFromParcel).isEqualTo(FM_BAND_DESCRIPTOR);
+ }
+
+ @Test
+ public void newArray_forFmBandDescriptorCreator() {
+ RadioManager.FmBandDescriptor[] fmBandDescriptors =
+ RadioManager.FmBandDescriptor.CREATOR.newArray(CREATOR_ARRAY_SIZE);
+
+ assertWithMessage("FM Band Descriptors")
+ .that(fmBandDescriptors).hasLength(CREATOR_ARRAY_SIZE);
+ }
+
+ @Test
public void isStereoSupported_forAmBandDescriptor() {
assertWithMessage("AM Band Descriptor stereo")
.that(AM_BAND_DESCRIPTOR.isStereoSupported()).isEqualTo(STEREO_SUPPORTED);
}
@Test
+ public void describeContents_forAmBandDescriptor() {
+ assertWithMessage("AM Band Descriptor contents")
+ .that(AM_BAND_DESCRIPTOR.describeContents()).isEqualTo(0);
+ }
+
+ @Test
+ public void writeToParcel_forAmBandDescriptor() {
+ Parcel parcel = Parcel.obtain();
+
+ AM_BAND_DESCRIPTOR.writeToParcel(parcel, /* flags= */ 0);
+ parcel.setDataPosition(0);
+
+ RadioManager.AmBandDescriptor amBandDescriptorFromParcel =
+ RadioManager.AmBandDescriptor.CREATOR.createFromParcel(parcel);
+ assertWithMessage("FM Band Descriptor created from parcel")
+ .that(amBandDescriptorFromParcel).isEqualTo(AM_BAND_DESCRIPTOR);
+ }
+
+ @Test
+ public void newArray_forAmBandDescriptorCreator() {
+ RadioManager.AmBandDescriptor[] amBandDescriptors =
+ RadioManager.AmBandDescriptor.CREATOR.newArray(CREATOR_ARRAY_SIZE);
+
+ assertWithMessage("AM Band Descriptors")
+ .that(amBandDescriptors).hasLength(CREATOR_ARRAY_SIZE);
+ }
+
+ @Test
public void equals_withSameFmBandDescriptors_returnsTrue() {
- RadioManager.FmBandDescriptor fmBandDescriptor1 = createFmBandDescriptor();
- RadioManager.FmBandDescriptor fmBandDescriptor2 = createFmBandDescriptor();
+ RadioManager.FmBandDescriptor fmBandDescriptorCompared = createFmBandDescriptor();
assertWithMessage("The same FM Band Descriptor")
- .that(fmBandDescriptor1).isEqualTo(fmBandDescriptor2);
+ .that(FM_BAND_DESCRIPTOR).isEqualTo(fmBandDescriptorCompared);
}
@Test
@@ -258,6 +332,44 @@
}
@Test
+ public void hashCode_withSameFmBandDescriptors_equals() {
+ RadioManager.FmBandDescriptor fmBandDescriptorCompared = createFmBandDescriptor();
+
+ assertWithMessage("Hash code of the same FM Band Descriptor")
+ .that(fmBandDescriptorCompared.hashCode()).isEqualTo(FM_BAND_DESCRIPTOR.hashCode());
+ }
+
+ @Test
+ public void hashCode_withSameAmBandDescriptors_equals() {
+ RadioManager.AmBandDescriptor amBandDescriptorCompared = createAmBandDescriptor();
+
+ assertWithMessage("Hash code of the same AM Band Descriptor")
+ .that(amBandDescriptorCompared.hashCode()).isEqualTo(AM_BAND_DESCRIPTOR.hashCode());
+ }
+
+ @Test
+ public void hashCode_withFmBandDescriptorsOfDifferentAfSupports_notEquals() {
+ RadioManager.FmBandDescriptor fmBandDescriptorCompared = new RadioManager.FmBandDescriptor(
+ REGION, RadioManager.BAND_FM, FM_LOWER_LIMIT, FM_UPPER_LIMIT, FM_SPACING,
+ STEREO_SUPPORTED, RDS_SUPPORTED, TA_SUPPORTED, !AF_SUPPORTED, EA_SUPPORTED);
+
+ assertWithMessage("Hash code of FM Band Descriptor of different spacing")
+ .that(fmBandDescriptorCompared.hashCode())
+ .isNotEqualTo(FM_BAND_DESCRIPTOR.hashCode());
+ }
+
+ @Test
+ public void hashCode_withAmBandDescriptorsOfDifferentSpacings_notEquals() {
+ RadioManager.AmBandDescriptor amBandDescriptorCompared =
+ new RadioManager.AmBandDescriptor(REGION, RadioManager.BAND_AM, AM_LOWER_LIMIT,
+ AM_UPPER_LIMIT, AM_SPACING * 2, STEREO_SUPPORTED);
+
+ assertWithMessage("Hash code of AM Band Descriptor of different spacing")
+ .that(amBandDescriptorCompared.hashCode())
+ .isNotEqualTo(AM_BAND_DESCRIPTOR.hashCode());
+ }
+
+ @Test
public void getType_forBandConfig() {
RadioManager.BandConfig fmBandConfig = createFmBandConfig();
@@ -298,8 +410,24 @@
}
@Test
+ public void describeContents_forBandConfig() {
+ RadioManager.BandConfig bandConfig = createFmBandConfig();
+
+ assertWithMessage("FM Band Config contents")
+ .that(bandConfig.describeContents()).isEqualTo(0);
+ }
+
+ @Test
+ public void newArray_forBandConfigCreator() {
+ RadioManager.BandConfig[] bandConfigs =
+ RadioManager.BandConfig.CREATOR.newArray(CREATOR_ARRAY_SIZE);
+
+ assertWithMessage("Band Configs").that(bandConfigs).hasLength(CREATOR_ARRAY_SIZE);
+ }
+
+ @Test
public void getStereo_forFmBandConfig() {
- assertWithMessage("FM Band Config stereo ")
+ assertWithMessage("FM Band Config stereo")
.that(FM_BAND_CONFIG.getStereo()).isEqualTo(STEREO_SUPPORTED);
}
@@ -328,12 +456,66 @@
}
@Test
+ public void describeContents_forFmBandConfig() {
+ assertWithMessage("FM Band Config contents")
+ .that(FM_BAND_CONFIG.describeContents()).isEqualTo(0);
+ }
+
+ @Test
+ public void writeToParcel_forFmBandConfig() {
+ Parcel parcel = Parcel.obtain();
+
+ FM_BAND_CONFIG.writeToParcel(parcel, /* flags= */ 0);
+ parcel.setDataPosition(0);
+
+ RadioManager.FmBandConfig fmBandConfigFromParcel =
+ RadioManager.FmBandConfig.CREATOR.createFromParcel(parcel);
+ assertWithMessage("FM Band Config created from parcel")
+ .that(fmBandConfigFromParcel).isEqualTo(FM_BAND_CONFIG);
+ }
+
+ @Test
+ public void newArray_forFmBandConfigCreator() {
+ RadioManager.FmBandConfig[] fmBandConfigs =
+ RadioManager.FmBandConfig.CREATOR.newArray(CREATOR_ARRAY_SIZE);
+
+ assertWithMessage("FM Band Configs").that(fmBandConfigs).hasLength(CREATOR_ARRAY_SIZE);
+ }
+
+ @Test
public void getStereo_forAmBandConfig() {
assertWithMessage("AM Band Config stereo")
.that(AM_BAND_CONFIG.getStereo()).isEqualTo(STEREO_SUPPORTED);
}
@Test
+ public void describeContents_forAmBandConfig() {
+ assertWithMessage("AM Band Config contents")
+ .that(AM_BAND_CONFIG.describeContents()).isEqualTo(0);
+ }
+
+ @Test
+ public void writeToParcel_forAmBandConfig() {
+ Parcel parcel = Parcel.obtain();
+
+ AM_BAND_CONFIG.writeToParcel(parcel, /* flags= */ 0);
+ parcel.setDataPosition(0);
+
+ RadioManager.AmBandConfig amBandConfigFromParcel =
+ RadioManager.AmBandConfig.CREATOR.createFromParcel(parcel);
+ assertWithMessage("AM Band Config created from parcel")
+ .that(amBandConfigFromParcel).isEqualTo(AM_BAND_CONFIG);
+ }
+
+ @Test
+ public void newArray_forAmBandConfigCreator() {
+ RadioManager.AmBandConfig[] amBandConfigs =
+ RadioManager.AmBandConfig.CREATOR.newArray(CREATOR_ARRAY_SIZE);
+
+ assertWithMessage("AM Band Configs").that(amBandConfigs).hasLength(CREATOR_ARRAY_SIZE);
+ }
+
+ @Test
public void equals_withSameFmBandConfigs_returnsTrue() {
RadioManager.FmBandConfig fmBandConfigCompared = createFmBandConfig();
@@ -387,6 +569,43 @@
}
@Test
+ public void hashCode_withSameFmBandConfigs_equals() {
+ RadioManager.FmBandConfig fmBandConfigCompared = createFmBandConfig();
+
+ assertWithMessage("Hash code of the same FM Band Config")
+ .that(FM_BAND_CONFIG.hashCode()).isEqualTo(fmBandConfigCompared.hashCode());
+ }
+
+ @Test
+ public void hashCode_withSameAmBandConfigs_equals() {
+ RadioManager.AmBandConfig amBandConfigCompared = createAmBandConfig();
+
+ assertWithMessage("Hash code of the same AM Band Config")
+ .that(amBandConfigCompared.hashCode()).isEqualTo(AM_BAND_CONFIG.hashCode());
+ }
+
+ @Test
+ public void hashCode_withFmBandConfigsOfDifferentTypes_notEquals() {
+ RadioManager.FmBandConfig fmBandConfigCompared = new RadioManager.FmBandConfig(
+ new RadioManager.FmBandDescriptor(REGION, RadioManager.BAND_FM_HD, FM_LOWER_LIMIT,
+ FM_UPPER_LIMIT, FM_SPACING, STEREO_SUPPORTED, RDS_SUPPORTED, TA_SUPPORTED,
+ AF_SUPPORTED, EA_SUPPORTED));
+
+ assertWithMessage("Hash code of FM Band Config with different type")
+ .that(fmBandConfigCompared.hashCode()).isNotEqualTo(FM_BAND_CONFIG.hashCode());
+ }
+
+ @Test
+ public void hashCode_withAmBandConfigsOfDifferentStereoSupports_notEquals() {
+ RadioManager.AmBandConfig amBandConfigCompared = new RadioManager.AmBandConfig(
+ new RadioManager.AmBandDescriptor(REGION, RadioManager.BAND_AM, AM_LOWER_LIMIT,
+ AM_UPPER_LIMIT, AM_SPACING, !STEREO_SUPPORTED));
+
+ assertWithMessage("Hash code of AM Band Config with different stereo support")
+ .that(amBandConfigCompared.hashCode()).isNotEqualTo(AM_BAND_CONFIG.hashCode());
+ }
+
+ @Test
public void getId_forModuleProperties() {
assertWithMessage("Properties id")
.that(AMFM_PROPERTIES.getId()).isEqualTo(PROPERTIES_ID);
@@ -509,6 +728,12 @@
}
@Test
+ public void describeContents_forModuleProperties() {
+ assertWithMessage("Module properties contents")
+ .that(AMFM_PROPERTIES.describeContents()).isEqualTo(0);
+ }
+
+ @Test
public void equals_withSameProperties_returnsTrue() {
RadioManager.ModuleProperties propertiesCompared = createAmFmProperties();
@@ -530,6 +755,23 @@
}
@Test
+ public void hashCode_withSameModuleProperties_equals() {
+ RadioManager.ModuleProperties propertiesCompared = createAmFmProperties();
+
+ assertWithMessage("Hash code of the same module properties")
+ .that(propertiesCompared.hashCode()).isEqualTo(AMFM_PROPERTIES.hashCode());
+ }
+
+ @Test
+ public void newArray_forModulePropertiesCreator() {
+ RadioManager.ModuleProperties[] modulePropertiesArray =
+ RadioManager.ModuleProperties.CREATOR.newArray(CREATOR_ARRAY_SIZE);
+
+ assertWithMessage("Module properties array")
+ .that(modulePropertiesArray).hasLength(CREATOR_ARRAY_SIZE);
+ }
+
+ @Test
public void getSelector_forProgramInfo() {
assertWithMessage("Selector of DAB program info")
.that(DAB_PROGRAM_INFO.getSelector()).isEqualTo(DAB_SELECTOR);
@@ -549,7 +791,7 @@
@Test
public void getRelatedContent_forProgramInfo() {
- assertWithMessage("Related contents of DAB program info")
+ assertWithMessage("DAB program info contents")
.that(DAB_PROGRAM_INFO.getRelatedContent())
.containsExactly(DAB_SID_EXT_IDENTIFIER_RELATED);
}
@@ -627,6 +869,33 @@
}
@Test
+ public void describeContents_forProgramInfo() {
+ assertWithMessage("Program info contents")
+ .that(DAB_PROGRAM_INFO.describeContents()).isEqualTo(0);
+ }
+
+ @Test
+ public void newArray_forProgramInfoCreator() {
+ RadioManager.ProgramInfo[] programInfoArray =
+ RadioManager.ProgramInfo.CREATOR.newArray(CREATOR_ARRAY_SIZE);
+
+ assertWithMessage("Program infos").that(programInfoArray).hasLength(CREATOR_ARRAY_SIZE);
+ }
+
+ @Test
+ public void writeToParcel_forProgramInfo() {
+ Parcel parcel = Parcel.obtain();
+
+ DAB_PROGRAM_INFO.writeToParcel(parcel, /* flags= */ 0);
+ parcel.setDataPosition(0);
+
+ RadioManager.ProgramInfo programInfoFromParcel =
+ RadioManager.ProgramInfo.CREATOR.createFromParcel(parcel);
+ assertWithMessage("Program info created from parcel")
+ .that(programInfoFromParcel).isEqualTo(DAB_PROGRAM_INFO);
+ }
+
+ @Test
public void equals_withSameProgramInfo_returnsTrue() {
RadioManager.ProgramInfo dabProgramInfoCompared = createDabProgramInfo(DAB_SELECTOR);
diff --git a/core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/unittests/RadioMetadataTest.java b/core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/unittests/RadioMetadataTest.java
index fe15597..5771135 100644
--- a/core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/unittests/RadioMetadataTest.java
+++ b/core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/unittests/RadioMetadataTest.java
@@ -20,18 +20,63 @@
import static org.junit.Assert.assertThrows;
+import android.graphics.Bitmap;
import android.hardware.radio.RadioMetadata;
+import android.os.Parcel;
import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
import java.util.Set;
+@RunWith(MockitoJUnitRunner.class)
public final class RadioMetadataTest {
+ private static final int CREATOR_ARRAY_SIZE = 3;
private static final int INT_KEY_VALUE = 1;
+ private static final long TEST_UTC_SECOND_SINCE_EPOCH = 200;
+ private static final int TEST_TIME_ZONE_OFFSET_MINUTES = 1;
private final RadioMetadata.Builder mBuilder = new RadioMetadata.Builder();
+ @Mock
+ private Bitmap mBitmapValue;
+
+ @Test
+ public void describeContents_forClock() {
+ RadioMetadata.Clock clock = new RadioMetadata.Clock(TEST_UTC_SECOND_SINCE_EPOCH,
+ TEST_TIME_ZONE_OFFSET_MINUTES);
+
+ assertWithMessage("Describe contents for metadata clock")
+ .that(clock.describeContents()).isEqualTo(0);
+ }
+
+ @Test
+ public void newArray_forClockCreator() {
+ RadioMetadata.Clock[] clocks = RadioMetadata.Clock.CREATOR.newArray(CREATOR_ARRAY_SIZE);
+
+ assertWithMessage("Clock array size").that(clocks.length).isEqualTo(CREATOR_ARRAY_SIZE);
+ }
+
+ @Test
+ public void writeToParcel_forClock() {
+ RadioMetadata.Clock clockExpected = new RadioMetadata.Clock(TEST_UTC_SECOND_SINCE_EPOCH,
+ TEST_TIME_ZONE_OFFSET_MINUTES);
+ Parcel parcel = Parcel.obtain();
+
+ clockExpected.writeToParcel(parcel, /* flags= */ 0);
+ parcel.setDataPosition(0);
+
+ RadioMetadata.Clock clockFromParcel = RadioMetadata.Clock.CREATOR.createFromParcel(parcel);
+ assertWithMessage("UTC second since epoch of metadata clock created from parcel")
+ .that(clockFromParcel.getUtcEpochSeconds()).isEqualTo(TEST_UTC_SECOND_SINCE_EPOCH);
+ assertWithMessage("Time zone offset minutes of metadata clock created from parcel")
+ .that(clockFromParcel.getTimezoneOffsetMinutes())
+ .isEqualTo(TEST_TIME_ZONE_OFFSET_MINUTES);
+ }
+
@Test
public void putString_withIllegalKey() {
String invalidStringKey = RadioMetadata.METADATA_KEY_RDS_PI;
@@ -129,22 +174,56 @@
}
@Test
+ public void getBitmap_withKeyInMetadata() {
+ String key = RadioMetadata.METADATA_KEY_ICON;
+ RadioMetadata metadata = mBuilder.putBitmap(key, mBitmapValue).build();
+
+ assertWithMessage("Bitmap value for key %s in metadata", key)
+ .that(metadata.getBitmap(key)).isEqualTo(mBitmapValue);
+ }
+
+ @Test
+ public void getBitmap_withKeyNotInMetadata() {
+ String key = RadioMetadata.METADATA_KEY_ICON;
+ RadioMetadata metadata = mBuilder.build();
+
+ assertWithMessage("Bitmap value for key %s not in metadata", key)
+ .that(metadata.getBitmap(key)).isNull();
+ }
+
+ @Test
+ public void getBitmapId_withKeyInMetadata() {
+ String key = RadioMetadata.METADATA_KEY_ART;
+ RadioMetadata metadata = mBuilder.putInt(key, INT_KEY_VALUE).build();
+
+ assertWithMessage("Bitmap id value for key %s in metadata", key)
+ .that(metadata.getBitmapId(key)).isEqualTo(INT_KEY_VALUE);
+ }
+
+ @Test
+ public void getBitmapId_withKeyNotInMetadata() {
+ String key = RadioMetadata.METADATA_KEY_ART;
+ RadioMetadata metadata = mBuilder.build();
+
+ assertWithMessage("Bitmap id value for key %s not in metadata", key)
+ .that(metadata.getBitmapId(key)).isEqualTo(0);
+ }
+
+ @Test
public void getClock_withKeyInMetadata() {
String key = RadioMetadata.METADATA_KEY_CLOCK;
- long utcSecondsSinceEpochExpected = 200;
- int timezoneOffsetMinutesExpected = 1;
RadioMetadata metadata = mBuilder
- .putClock(key, utcSecondsSinceEpochExpected, timezoneOffsetMinutesExpected)
+ .putClock(key, TEST_UTC_SECOND_SINCE_EPOCH, TEST_TIME_ZONE_OFFSET_MINUTES)
.build();
RadioMetadata.Clock clockExpected = metadata.getClock(key);
assertWithMessage("Number of seconds since epoch of value for key %s in metadata", key)
.that(clockExpected.getUtcEpochSeconds())
- .isEqualTo(utcSecondsSinceEpochExpected);
+ .isEqualTo(TEST_UTC_SECOND_SINCE_EPOCH);
assertWithMessage("Offset of timezone in minutes of value for key %s in metadata", key)
.that(clockExpected.getTimezoneOffsetMinutes())
- .isEqualTo(timezoneOffsetMinutesExpected);
+ .isEqualTo(TEST_TIME_ZONE_OFFSET_MINUTES);
}
@Test
@@ -180,12 +259,13 @@
RadioMetadata metadata = mBuilder
.putInt(RadioMetadata.METADATA_KEY_RDS_PI, INT_KEY_VALUE)
.putString(RadioMetadata.METADATA_KEY_ARTIST, "artistTest")
+ .putBitmap(RadioMetadata.METADATA_KEY_ICON, mBitmapValue)
.build();
Set<String> metadataSet = metadata.keySet();
assertWithMessage("Metadata set of non-empty metadata")
- .that(metadataSet).containsExactly(
+ .that(metadataSet).containsExactly(RadioMetadata.METADATA_KEY_ICON,
RadioMetadata.METADATA_KEY_RDS_PI, RadioMetadata.METADATA_KEY_ARTIST);
}
@@ -208,4 +288,46 @@
.that(key).isEqualTo(RadioMetadata.METADATA_KEY_RDS_PI);
}
+ @Test
+ public void equals_forMetadataWithSameContents_returnsTrue() {
+ RadioMetadata metadata = mBuilder
+ .putInt(RadioMetadata.METADATA_KEY_RDS_PI, INT_KEY_VALUE)
+ .putString(RadioMetadata.METADATA_KEY_ARTIST, "artistTest")
+ .build();
+ RadioMetadata.Builder copyBuilder = new RadioMetadata.Builder(metadata);
+ RadioMetadata metadataCopied = copyBuilder.build();
+
+ assertWithMessage("Metadata with the same contents")
+ .that(metadataCopied).isEqualTo(metadata);
+ }
+
+ @Test
+ public void describeContents_forMetadata() {
+ RadioMetadata metadata = mBuilder.build();
+
+ assertWithMessage("Metadata contents").that(metadata.describeContents()).isEqualTo(0);
+ }
+
+ @Test
+ public void newArray_forRadioMetadataCreator() {
+ RadioMetadata[] metadataArray = RadioMetadata.CREATOR.newArray(CREATOR_ARRAY_SIZE);
+
+ assertWithMessage("Radio metadata array").that(metadataArray).hasLength(CREATOR_ARRAY_SIZE);
+ }
+
+ @Test
+ public void writeToParcel_forRadioMetadata() {
+ RadioMetadata metadataExpected = mBuilder
+ .putInt(RadioMetadata.METADATA_KEY_RDS_PI, INT_KEY_VALUE)
+ .putString(RadioMetadata.METADATA_KEY_ARTIST, "artistTest")
+ .build();
+ Parcel parcel = Parcel.obtain();
+
+ metadataExpected.writeToParcel(parcel, /* flags= */ 0);
+ parcel.setDataPosition(0);
+
+ RadioMetadata metadataFromParcel = RadioMetadata.CREATOR.createFromParcel(parcel);
+ assertWithMessage("Radio metadata created from parcel")
+ .that(metadataFromParcel).isEqualTo(metadataExpected);
+ }
}
diff --git a/core/tests/coretests/src/android/app/activity/BroadcastTest.java b/core/tests/coretests/src/android/app/activity/BroadcastTest.java
index 0f81896..7e875ad 100644
--- a/core/tests/coretests/src/android/app/activity/BroadcastTest.java
+++ b/core/tests/coretests/src/android/app/activity/BroadcastTest.java
@@ -18,6 +18,8 @@
import android.app.Activity;
import android.app.ActivityManager;
+import android.app.BroadcastOptions;
+import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -536,4 +538,40 @@
Log.i("foo", "Unregister exception", e);
}
}
+
+ public void testBroadcastOption_interactive() throws Exception {
+ final BroadcastOptions options = BroadcastOptions.makeBasic();
+ options.setInteractiveBroadcast(true);
+ final Intent intent = makeBroadcastIntent(BROADCAST_REGISTERED);
+
+ try {
+ getContext().sendBroadcast(intent, null, options.toBundle());
+ fail("No exception thrown with BroadcastOptions.setInteractiveBroadcast(true)");
+ } catch (SecurityException se) {
+ // Expected, correct behavior - this case intentionally empty
+ } catch (Exception e) {
+ fail("Unexpected exception " + e.getMessage()
+ + " thrown with BroadcastOptions.setInteractiveBroadcast(true)");
+ }
+ }
+
+ public void testBroadcastOption_interactive_PendingIntent() throws Exception {
+ final BroadcastOptions options = BroadcastOptions.makeBasic();
+ options.setInteractiveBroadcast(true);
+ final Intent intent = makeBroadcastIntent(BROADCAST_REGISTERED);
+ PendingIntent brPending = PendingIntent.getBroadcast(getContext(),
+ 1, intent, PendingIntent.FLAG_IMMUTABLE);
+
+ try {
+ brPending.send(getContext(), 1, null, null, null, null, options.toBundle());
+ fail("No exception thrown with BroadcastOptions.setInteractiveBroadcast(true)");
+ } catch (SecurityException se) {
+ // Expected, correct behavior - this case intentionally empty
+ } catch (Exception e) {
+ fail("Unexpected exception " + e.getMessage()
+ + " thrown with BroadcastOptions.setInteractiveBroadcast(true)");
+ } finally {
+ brPending.cancel();
+ }
+ }
}
diff --git a/core/tests/coretests/src/android/view/accessibility/AccessibilityManagerTest.java b/core/tests/coretests/src/android/view/accessibility/AccessibilityManagerTest.java
index bb1a3b18..ee1e10f 100644
--- a/core/tests/coretests/src/android/view/accessibility/AccessibilityManagerTest.java
+++ b/core/tests/coretests/src/android/view/accessibility/AccessibilityManagerTest.java
@@ -27,6 +27,7 @@
import static org.mockito.Mockito.when;
import android.accessibilityservice.AccessibilityServiceInfo;
+import android.accessibilityservice.IAccessibilityServiceClient;
import android.app.Instrumentation;
import android.app.PendingIntent;
import android.app.RemoteAction;
@@ -34,6 +35,7 @@
import android.graphics.drawable.Icon;
import android.os.UserHandle;
+import androidx.annotation.NonNull;
import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
@@ -51,6 +53,7 @@
import java.util.ArrayList;
import java.util.List;
+import java.util.concurrent.Executors;
/**
* Tests for the AccessibilityManager by mocking the backing service.
@@ -70,6 +73,7 @@
LABEL,
DESCRIPTION,
TEST_PENDING_INTENT);
+ private static final int DISPLAY_ID = 22;
@Mock private IAccessibilityManager mMockService;
private MessageCapturingHandler mHandler;
@@ -224,4 +228,45 @@
assertEquals(mFocusColorDefaultValue,
manager.getAccessibilityFocusColor());
}
+
+ @Test
+ public void testRegisterAccessibilityProxy() throws Exception {
+ // Accessibility does not need to be enabled for a proxy to be registered.
+ AccessibilityManager manager =
+ new AccessibilityManager(mInstrumentation.getContext(), mHandler, mMockService,
+ UserHandle.USER_CURRENT, true);
+
+
+ ArrayList<AccessibilityServiceInfo> infos = new ArrayList<>();
+ infos.add(new AccessibilityServiceInfo());
+ AccessibilityDisplayProxy proxy = new MyAccessibilityProxy(DISPLAY_ID, infos);
+ manager.registerDisplayProxy(proxy);
+ // Cannot access proxy.mServiceClient directly due to visibility.
+ verify(mMockService).registerProxyForDisplay(any(IAccessibilityServiceClient.class),
+ any(Integer.class));
+ }
+
+ @Test
+ public void testUnregisterAccessibilityProxy() throws Exception {
+ // Accessibility does not need to be enabled for a proxy to be registered.
+ final AccessibilityManager manager =
+ new AccessibilityManager(mInstrumentation.getContext(), mHandler, mMockService,
+ UserHandle.USER_CURRENT, true);
+
+ final ArrayList<AccessibilityServiceInfo> infos = new ArrayList<>();
+ infos.add(new AccessibilityServiceInfo());
+
+ final AccessibilityDisplayProxy proxy = new MyAccessibilityProxy(DISPLAY_ID, infos);
+ manager.registerDisplayProxy(proxy);
+ manager.unregisterDisplayProxy(proxy);
+ verify(mMockService).unregisterProxyForDisplay(proxy.getDisplayId());
+ }
+
+ private class MyAccessibilityProxy extends AccessibilityDisplayProxy {
+ // TODO(241429275): Will override A11yProxy methods in the future.
+ MyAccessibilityProxy(int displayId,
+ @NonNull List<AccessibilityServiceInfo> serviceInfos) {
+ super(displayId, Executors.newSingleThreadExecutor(), serviceInfos);
+ }
+ }
}
diff --git a/core/tests/coretests/src/android/view/inputmethod/ParcelableHandwritingGestureTest.java b/core/tests/coretests/src/android/view/inputmethod/ParcelableHandwritingGestureTest.java
new file mode 100644
index 0000000..79aeaa3
--- /dev/null
+++ b/core/tests/coretests/src/android/view/inputmethod/ParcelableHandwritingGestureTest.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.inputmethod;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThrows;
+
+import android.annotation.NonNull;
+import android.graphics.PointF;
+import android.graphics.RectF;
+import android.os.Parcel;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class ParcelableHandwritingGestureTest {
+
+ @Test
+ public void testCreationFailWithNullPointerException() {
+ assertThrows(NullPointerException.class, () -> ParcelableHandwritingGesture.of(null));
+ }
+
+ @Test
+ public void testInvalidTypeHeader() {
+ Parcel parcel = null;
+ try {
+ parcel = Parcel.obtain();
+ // GESTURE_TYPE_NONE is not a supported header.
+ parcel.writeInt(HandwritingGesture.GESTURE_TYPE_NONE);
+ final Parcel initializedParcel = parcel;
+ assertThrows(UnsupportedOperationException.class,
+ () -> ParcelableHandwritingGesture.CREATOR.createFromParcel(initializedParcel));
+ } finally {
+ if (parcel != null) {
+ parcel.recycle();
+ }
+ }
+ }
+
+ @Test
+ public void testSelectGesture() {
+ verifyEqualityAfterUnparcel(new SelectGesture.Builder()
+ .setGranularity(HandwritingGesture.GRANULARITY_WORD)
+ .setSelectionArea(new RectF(1, 2, 3, 4))
+ .setFallbackText("")
+ .build());
+ }
+
+ @Test
+ public void testSelectRangeGesture() {
+ verifyEqualityAfterUnparcel(new SelectRangeGesture.Builder()
+ .setGranularity(HandwritingGesture.GRANULARITY_WORD)
+ .setSelectionStartArea(new RectF(1, 2, 3, 4))
+ .setSelectionEndArea(new RectF(5, 6, 7, 8))
+ .setFallbackText("")
+ .build());
+ }
+
+ @Test
+ public void testInsertGestureGesture() {
+ verifyEqualityAfterUnparcel(new InsertGesture.Builder()
+ .setTextToInsert("text")
+ .setInsertionPoint(new PointF(1, 1)).setFallbackText("")
+ .build());
+ }
+
+ @Test
+ public void testDeleteGestureGesture() {
+ verifyEqualityAfterUnparcel(new DeleteGesture.Builder()
+ .setGranularity(HandwritingGesture.GRANULARITY_WORD)
+ .setDeletionArea(new RectF(1, 2, 3, 4))
+ .setFallbackText("")
+ .build());
+ }
+
+ @Test
+ public void testDeleteRangeGestureGesture() {
+ verifyEqualityAfterUnparcel(new DeleteRangeGesture.Builder()
+ .setGranularity(HandwritingGesture.GRANULARITY_WORD)
+ .setDeletionStartArea(new RectF(1, 2, 3, 4))
+ .setDeletionEndArea(new RectF(5, 6, 7, 8))
+ .setFallbackText("")
+ .build());
+ }
+
+ @Test
+ public void testRemoveSpaceGestureGesture() {
+ verifyEqualityAfterUnparcel(new RemoveSpaceGesture.Builder()
+ .setPoints(new PointF(1f, 2f), new PointF(3f, 4f))
+ .setFallbackText("")
+ .build());
+ }
+
+ @Test
+ public void testJoinOrSplitGestureGesture() {
+ verifyEqualityAfterUnparcel(new JoinOrSplitGesture.Builder()
+ .setJoinOrSplitPoint(new PointF(1f, 2f))
+ .setFallbackText("")
+ .build());
+ }
+
+ static void verifyEqualityAfterUnparcel(@NonNull HandwritingGesture gesture) {
+ assertEquals(gesture, cloneViaParcel(ParcelableHandwritingGesture.of(gesture)).get());
+ }
+
+ private static ParcelableHandwritingGesture cloneViaParcel(
+ @NonNull ParcelableHandwritingGesture original) {
+ Parcel parcel = null;
+ try {
+ parcel = Parcel.obtain();
+ original.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ return ParcelableHandwritingGesture.CREATOR.createFromParcel(parcel);
+ } finally {
+ if (parcel != null) {
+ parcel.recycle();
+ }
+ }
+ }
+}
diff --git a/core/tests/coretests/src/android/view/stylus/HandwritingInitiatorTest.java b/core/tests/coretests/src/android/view/stylus/HandwritingInitiatorTest.java
index d4a6632..95aa5d0 100644
--- a/core/tests/coretests/src/android/view/stylus/HandwritingInitiatorTest.java
+++ b/core/tests/coretests/src/android/view/stylus/HandwritingInitiatorTest.java
@@ -32,6 +32,7 @@
import android.content.Context;
import android.graphics.Rect;
import android.platform.test.annotations.Presubmit;
+import android.view.HandwritingDelegateConfiguration;
import android.view.HandwritingInitiator;
import android.view.InputDevice;
import android.view.MotionEvent;
@@ -208,6 +209,30 @@
}
@Test
+ public void onTouchEvent_startHandwriting_delegate() {
+ int delegatorViewId = 234;
+ View delegatorView = new View(mContext);
+ delegatorView.setId(delegatorViewId);
+
+ mTestView.setHandwritingDelegateConfiguration(
+ new HandwritingDelegateConfiguration(
+ delegatorViewId,
+ () -> mHandwritingInitiator.onInputConnectionCreated(delegatorView)));
+
+ final int x1 = (sHwArea.left + sHwArea.right) / 2;
+ final int y1 = (sHwArea.top + sHwArea.bottom) / 2;
+ MotionEvent stylusEvent1 = createStylusEvent(ACTION_DOWN, x1, y1, 0);
+ mHandwritingInitiator.onTouchEvent(stylusEvent1);
+
+ final int x2 = x1 + mHandwritingSlop * 2;
+ final int y2 = y1;
+ MotionEvent stylusEvent2 = createStylusEvent(ACTION_MOVE, x2, y2, 0);
+ mHandwritingInitiator.onTouchEvent(stylusEvent2);
+
+ verify(mHandwritingInitiator, times(1)).startHandwriting(delegatorView);
+ }
+
+ @Test
public void onTouchEvent_notStartHandwriting_whenHandwritingNotAvailable() {
final Rect rect = new Rect(600, 600, 900, 900);
final View testView = createView(rect, true /* autoHandwritingEnabled */,
diff --git a/core/tests/coretests/src/com/android/internal/security/OWNERS b/core/tests/coretests/src/com/android/internal/security/OWNERS
new file mode 100644
index 0000000..4f4d8d7
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/security/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 36824
+
+per-file VerityUtilsTest.java = file:platform/system/security:/fsverity/OWNERS
diff --git a/graphics/java/android/view/PixelCopy.java b/graphics/java/android/view/PixelCopy.java
index 0f82c8f..889edb3 100644
--- a/graphics/java/android/view/PixelCopy.java
+++ b/graphics/java/android/view/PixelCopy.java
@@ -311,11 +311,11 @@
/**
* Contains the result of a PixelCopy request
*/
- public static final class CopyResult {
+ public static final class Result {
private int mStatus;
private Bitmap mBitmap;
- private CopyResult(@CopyResultStatus int status, Bitmap bitmap) {
+ private Result(@CopyResultStatus int status, Bitmap bitmap) {
mStatus = status;
mBitmap = bitmap;
}
@@ -335,8 +335,8 @@
/**
* If the PixelCopy {@link Request} was given a destination bitmap with
- * {@link Request#setDestinationBitmap(Bitmap)} then the returned bitmap will be the same
- * as the one given. If no destination bitmap was provided, then this
+ * {@link Request.Builder#setDestinationBitmap(Bitmap)} then the returned bitmap will be
+ * the same as the one given. If no destination bitmap was provided, then this
* will contain the automatically allocated Bitmap to hold the result.
*
* @return the Bitmap the copy request was stored in.
@@ -349,66 +349,199 @@
}
/**
- * A builder to create the complete PixelCopy request, which is then executed by calling
- * {@link #request()}
+ * Represents a PixelCopy request.
+ *
+ * To create a copy request, use either of the PixelCopy.Request.ofWindow or
+ * PixelCopy.Request.ofSurface factories to create a {@link Request.Builder} for the
+ * given source content. After setting any optional parameters, such as
+ * {@link Builder#setSourceRect(Rect)}, build the request with {@link Builder#build()} and
+ * then execute it with {@link PixelCopy#request(Request)}
*/
public static final class Request {
+ private final Surface mSource;
+ private final Consumer<Result> mListener;
+ private final Executor mListenerThread;
+ private final Rect mSourceInsets;
+ private Rect mSrcRect;
+ private Bitmap mDest;
+
private Request(Surface source, Rect sourceInsets, Executor listenerThread,
- Consumer<CopyResult> listener) {
+ Consumer<Result> listener) {
this.mSource = source;
this.mSourceInsets = sourceInsets;
this.mListenerThread = listenerThread;
this.mListener = listener;
}
- private final Surface mSource;
- private final Consumer<CopyResult> mListener;
- private final Executor mListenerThread;
- private final Rect mSourceInsets;
- private Rect mSrcRect;
- private Bitmap mDest;
-
/**
- * Sets the region of the source to copy from. By default, the entire source is copied to
- * the output. If only a subset of the source is necessary to be copied, specifying a
- * srcRect will improve performance by reducing
- * the amount of data being copied.
- *
- * @param srcRect The area of the source to read from. Null or empty will be treated to
- * mean the entire source
- * @return this
+ * A builder to create the complete PixelCopy request, which is then executed by calling
+ * {@link #request(Request)} with the built request returned from {@link #build()}
*/
- public @NonNull Request setSourceRect(@Nullable Rect srcRect) {
- this.mSrcRect = srcRect;
- return this;
- }
+ public static final class Builder {
+ private Request mRequest;
- /**
- * Specifies the output bitmap in which to store the result. By default, a Bitmap of format
- * {@link android.graphics.Bitmap.Config#ARGB_8888} with a width & height matching that
- * of the {@link #setSourceRect(Rect) source area} will be created to place the result.
- *
- * @param destination The bitmap to store the result, or null to have a bitmap
- * automatically created of the appropriate size. If not null, must not
- * be {@link Bitmap#isRecycled() recycled} and must be
- * {@link Bitmap#isMutable() mutable}.
- * @return this
- */
- public @NonNull Request setDestinationBitmap(@Nullable Bitmap destination) {
- if (destination != null) {
- validateBitmapDest(destination);
+ private Builder(Request request) {
+ mRequest = request;
}
- this.mDest = destination;
- return this;
+
+ private void requireNotBuilt() {
+ if (mRequest == null) {
+ throw new IllegalStateException("build() already called on this builder");
+ }
+ }
+
+ /**
+ * Sets the region of the source to copy from. By default, the entire source is copied
+ * to the output. If only a subset of the source is necessary to be copied, specifying
+ * a srcRect will improve performance by reducing
+ * the amount of data being copied.
+ *
+ * @param srcRect The area of the source to read from. Null or empty will be treated to
+ * mean the entire source
+ * @return this
+ */
+ public @NonNull Builder setSourceRect(@Nullable Rect srcRect) {
+ requireNotBuilt();
+ mRequest.mSrcRect = srcRect;
+ return this;
+ }
+
+ /**
+ * Specifies the output bitmap in which to store the result. By default, a Bitmap of
+ * format {@link android.graphics.Bitmap.Config#ARGB_8888} with a width & height
+ * matching that of the {@link #setSourceRect(Rect) source area} will be created to
+ * place the result.
+ *
+ * @param destination The bitmap to store the result, or null to have a bitmap
+ * automatically created of the appropriate size. If not null, must
+ * not be {@link Bitmap#isRecycled() recycled} and must be
+ * {@link Bitmap#isMutable() mutable}.
+ * @return this
+ */
+ public @NonNull Builder setDestinationBitmap(@Nullable Bitmap destination) {
+ requireNotBuilt();
+ if (destination != null) {
+ validateBitmapDest(destination);
+ }
+ mRequest.mDest = destination;
+ return this;
+ }
+
+ /**
+ * @return The built {@link PixelCopy.Request}
+ */
+ public @NonNull Request build() {
+ requireNotBuilt();
+ Request ret = mRequest;
+ mRequest = null;
+ return ret;
+ }
}
/**
- * Executes the request.
+ * Creates a PixelCopy request for the given {@link Window}
+ * @param source The Window to copy from
+ * @param callbackExecutor The executor to run the callback on
+ * @param listener The callback for when the copy request is completed
+ * @return A {@link Builder} builder to set the optional params & execute the request
+ */
+ public static @NonNull Builder ofWindow(@NonNull Window source,
+ @NonNull Executor callbackExecutor,
+ @NonNull Consumer<Result> listener) {
+ final Rect insets = new Rect();
+ final Surface surface = sourceForWindow(source, insets);
+ return new Builder(new Request(surface, insets, callbackExecutor, listener));
+ }
+
+ /**
+ * Creates a PixelCopy request for the {@link Window} that the given {@link View} is
+ * attached to.
+ *
+ * Note that this copy request is not cropped to the area the View occupies by default. If
+ * that behavior is desired, use {@link View#getLocationInWindow(int[])} combined with
+ * {@link Builder#setSourceRect(Rect)} to set a crop area to restrict the copy operation.
+ *
+ * @param source A View that {@link View#isAttachedToWindow() is attached} to a window that
+ * will be used to retrieve the window to copy from.
+ * @param callbackExecutor The executor to run the callback on
+ * @param listener The callback for when the copy request is completed
+ * @return A {@link Builder} builder to set the optional params & execute the request
+ */
+ public static @NonNull Builder ofWindow(@NonNull View source,
+ @NonNull Executor callbackExecutor,
+ @NonNull Consumer<Result> listener) {
+ if (source == null || !source.isAttachedToWindow()) {
+ throw new IllegalArgumentException(
+ "View must not be null & must be attached to window");
+ }
+ final Rect insets = new Rect();
+ Surface surface = null;
+ final ViewRootImpl root = source.getViewRootImpl();
+ if (root != null) {
+ surface = root.mSurface;
+ insets.set(root.mWindowAttributes.surfaceInsets);
+ }
+ if (surface == null || !surface.isValid()) {
+ throw new IllegalArgumentException(
+ "Window doesn't have a backing surface!");
+ }
+ return new Builder(new Request(surface, insets, callbackExecutor, listener));
+ }
+
+ /**
+ * Creates a PixelCopy request for the given {@link Surface}
+ *
+ * @param source The Surface to copy from. Must be {@link Surface#isValid() valid}.
+ * @param callbackExecutor The executor to run the callback on
+ * @param listener The callback for when the copy request is completed
+ * @return A {@link Builder} builder to set the optional params & execute the request
+ */
+ public static @NonNull Builder ofSurface(@NonNull Surface source,
+ @NonNull Executor callbackExecutor,
+ @NonNull Consumer<Result> listener) {
+ if (source == null || !source.isValid()) {
+ throw new IllegalArgumentException("Source must not be null & must be valid");
+ }
+ return new Builder(new Request(source, null, callbackExecutor, listener));
+ }
+
+ /**
+ * Creates a PixelCopy request for the {@link Surface} belonging to the
+ * given {@link SurfaceView}
+ *
+ * @param source The SurfaceView to copy from. The backing surface must be
+ * {@link Surface#isValid() valid}
+ * @param callbackExecutor The executor to run the callback on
+ * @param listener The callback for when the copy request is completed
+ * @return A {@link Builder} builder to set the optional params & execute the request
+ */
+ public static @NonNull Builder ofSurface(@NonNull SurfaceView source,
+ @NonNull Executor callbackExecutor,
+ @NonNull Consumer<Result> listener) {
+ return ofSurface(source.getHolder().getSurface(), callbackExecutor, listener);
+ }
+
+ /**
+ * @return The destination bitmap as set by {@link Builder#setDestinationBitmap(Bitmap)}
+ */
+ public @Nullable Bitmap getDestinationBitmap() {
+ return mDest;
+ }
+
+ /**
+ * @return The source rect to copy from as set by {@link Builder#setSourceRect(Rect)}
+ */
+ public @Nullable Rect getSourceRect() {
+ return mSrcRect;
+ }
+
+ /**
+ * @hide
*/
public void request() {
if (!mSource.isValid()) {
mListenerThread.execute(() -> mListener.accept(
- new CopyResult(ERROR_SOURCE_INVALID, null)));
+ new Result(ERROR_SOURCE_INVALID, null)));
return;
}
HardwareRenderer.copySurfaceInto(mSource, new HardwareRenderer.CopyRequest(
@@ -416,93 +549,18 @@
@Override
public void onCopyFinished(int result) {
mListenerThread.execute(() -> mListener.accept(
- new CopyResult(result, mDestinationBitmap)));
+ new Result(result, mDestinationBitmap)));
}
});
}
}
/**
- * Creates a PixelCopy request for the given {@link Window}
- * @param source The Window to copy from
- * @param callbackExecutor The executor to run the callback on
- * @param listener The callback for when the copy request is completed
- * @return A {@link Request} builder to set the optional params & execute the request
+ * Executes the pixel copy request
+ * @param request The request to execute
*/
- public static @NonNull Request ofWindow(@NonNull Window source,
- @NonNull Executor callbackExecutor,
- @NonNull Consumer<CopyResult> listener) {
- final Rect insets = new Rect();
- final Surface surface = sourceForWindow(source, insets);
- return new Request(surface, insets, callbackExecutor, listener);
- }
-
- /**
- * Creates a PixelCopy request for the {@link Window} that the given {@link View} is
- * attached to.
- *
- * Note that this copy request is not cropped to the area the View occupies by default. If that
- * behavior is desired, use {@link View#getLocationInWindow(int[])} combined with
- * {@link Request#setSourceRect(Rect)} to set a crop area to restrict the copy operation.
- *
- * @param source A View that {@link View#isAttachedToWindow() is attached} to a window that
- * will be used to retrieve the window to copy from.
- * @param callbackExecutor The executor to run the callback on
- * @param listener The callback for when the copy request is completed
- * @return A {@link Request} builder to set the optional params & execute the request
- */
- public static @NonNull Request ofWindow(@NonNull View source,
- @NonNull Executor callbackExecutor,
- @NonNull Consumer<CopyResult> listener) {
- if (source == null || !source.isAttachedToWindow()) {
- throw new IllegalArgumentException(
- "View must not be null & must be attached to window");
- }
- final Rect insets = new Rect();
- Surface surface = null;
- final ViewRootImpl root = source.getViewRootImpl();
- if (root != null) {
- surface = root.mSurface;
- insets.set(root.mWindowAttributes.surfaceInsets);
- }
- if (surface == null || !surface.isValid()) {
- throw new IllegalArgumentException(
- "Window doesn't have a backing surface!");
- }
- return new Request(surface, insets, callbackExecutor, listener);
- }
-
- /**
- * Creates a PixelCopy request for the given {@link Surface}
- *
- * @param source The Surface to copy from. Must be {@link Surface#isValid() valid}.
- * @param callbackExecutor The executor to run the callback on
- * @param listener The callback for when the copy request is completed
- * @return A {@link Request} builder to set the optional params & execute the request
- */
- public static @NonNull Request ofSurface(@NonNull Surface source,
- @NonNull Executor callbackExecutor,
- @NonNull Consumer<CopyResult> listener) {
- if (source == null || !source.isValid()) {
- throw new IllegalArgumentException("Source must not be null & must be valid");
- }
- return new Request(source, null, callbackExecutor, listener);
- }
-
- /**
- * Creates a PixelCopy request for the {@link Surface} belonging to the
- * given {@link SurfaceView}
- *
- * @param source The SurfaceView to copy from. The backing surface must be
- * {@link Surface#isValid() valid}
- * @param callbackExecutor The executor to run the callback on
- * @param listener The callback for when the copy request is completed
- * @return A {@link Request} builder to set the optional params & execute the request
- */
- public static @NonNull Request ofSurface(@NonNull SurfaceView source,
- @NonNull Executor callbackExecutor,
- @NonNull Consumer<CopyResult> listener) {
- return ofSurface(source.getHolder().getSurface(), callbackExecutor, listener);
+ public static void request(@NonNull Request request) {
+ request.request();
}
private PixelCopy() {}
diff --git a/libs/WindowManager/Shell/res/drawable/caption_desktop_button.xml b/libs/WindowManager/Shell/res/drawable/caption_desktop_button.xml
new file mode 100644
index 0000000..8779cc0
--- /dev/null
+++ b/libs/WindowManager/Shell/res/drawable/caption_desktop_button.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="32.0dp"
+ android:height="32.0dp"
+ android:viewportWidth="32.0"
+ android:viewportHeight="32.0"
+>
+ <group android:scaleX="0.5"
+ android:scaleY="0.5"
+ android:translateX="6.0"
+ android:translateY="6.0">
+ <path
+ android:fillColor="@android:color/black"
+ android:pathData="M5.958,37.708Q4.458,37.708 3.354,36.604Q2.25,35.5 2.25,34V18.292Q2.25,16.792 3.354,15.688Q4.458,14.583 5.958,14.583H9.5V5.958Q9.5,4.458 10.625,3.354Q11.75,2.25 13.208,2.25H34Q35.542,2.25 36.646,3.354Q37.75,4.458 37.75,5.958V21.667Q37.75,23.167 36.646,24.271Q35.542,25.375 34,25.375H30.5V34Q30.5,35.5 29.396,36.604Q28.292,37.708 26.792,37.708ZM5.958,34H26.792Q26.792,34 26.792,34Q26.792,34 26.792,34V21.542H5.958V34Q5.958,34 5.958,34Q5.958,34 5.958,34ZM30.5,21.667H34Q34,21.667 34,21.667Q34,21.667 34,21.667V9.208H13.208V14.583H26.833Q28.375,14.583 29.438,15.667Q30.5,16.75 30.5,18.25Z"/>
+ </group>
+</vector>
diff --git a/libs/WindowManager/Shell/res/drawable/caption_floating_button.xml b/libs/WindowManager/Shell/res/drawable/caption_floating_button.xml
new file mode 100644
index 0000000..ea0fbb0
--- /dev/null
+++ b/libs/WindowManager/Shell/res/drawable/caption_floating_button.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="32.0dp"
+ android:height="32.0dp"
+ android:viewportWidth="32.0"
+ android:viewportHeight="32.0"
+>
+ <group android:scaleX="0.5"
+ android:scaleY="0.5"
+ android:translateX="6.0"
+ android:translateY="6.0">
+ <path
+ android:fillColor="@android:color/black"
+ android:pathData="M18.167,21.875H29.833V10.208H18.167ZM7.875,35.833Q6.375,35.833 5.271,34.729Q4.167,33.625 4.167,32.125V7.875Q4.167,6.375 5.271,5.271Q6.375,4.167 7.875,4.167H32.125Q33.625,4.167 34.729,5.271Q35.833,6.375 35.833,7.875V32.125Q35.833,33.625 34.729,34.729Q33.625,35.833 32.125,35.833ZM7.875,32.125H32.125Q32.125,32.125 32.125,32.125Q32.125,32.125 32.125,32.125V7.875Q32.125,7.875 32.125,7.875Q32.125,7.875 32.125,7.875H7.875Q7.875,7.875 7.875,7.875Q7.875,7.875 7.875,7.875V32.125Q7.875,32.125 7.875,32.125Q7.875,32.125 7.875,32.125ZM7.875,7.875Q7.875,7.875 7.875,7.875Q7.875,7.875 7.875,7.875V32.125Q7.875,32.125 7.875,32.125Q7.875,32.125 7.875,32.125Q7.875,32.125 7.875,32.125Q7.875,32.125 7.875,32.125V7.875Q7.875,7.875 7.875,7.875Q7.875,7.875 7.875,7.875Z"/>
+ </group>
+</vector>
diff --git a/libs/WindowManager/Shell/res/drawable/caption_fullscreen_button.xml b/libs/WindowManager/Shell/res/drawable/caption_fullscreen_button.xml
new file mode 100644
index 0000000..c55cbe2
--- /dev/null
+++ b/libs/WindowManager/Shell/res/drawable/caption_fullscreen_button.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="32.0dp"
+ android:height="32.0dp"
+ android:viewportWidth="32.0"
+ android:viewportHeight="32.0"
+>
+ <group android:scaleX="0.5"
+ android:scaleY="0.5"
+ android:translateX="6.0"
+ android:translateY="6.0">
+ <path
+ android:fillColor="@android:color/black"
+ android:pathData="M34.042,14.625V9.333Q34.042,9.333 34.042,9.333Q34.042,9.333 34.042,9.333H28.708V5.708H33.917Q35.458,5.708 36.562,6.833Q37.667,7.958 37.667,9.458V14.625ZM2.375,14.625V9.458Q2.375,7.958 3.479,6.833Q4.583,5.708 6.125,5.708H11.292V9.333H6Q6,9.333 6,9.333Q6,9.333 6,9.333V14.625ZM28.708,34.25V30.667H34.042Q34.042,30.667 34.042,30.667Q34.042,30.667 34.042,30.667V25.333H37.667V30.542Q37.667,32 36.562,33.125Q35.458,34.25 33.917,34.25ZM6.125,34.25Q4.583,34.25 3.479,33.125Q2.375,32 2.375,30.542V25.333H6V30.667Q6,30.667 6,30.667Q6,30.667 6,30.667H11.292V34.25ZM9.333,27.292V12.667H30.708V27.292ZM12.917,23.708H27.125V16.25H12.917ZM12.917,23.708V16.25V23.708Z"/>
+ </group>
+</vector>
diff --git a/libs/WindowManager/Shell/res/drawable/caption_more_button.xml b/libs/WindowManager/Shell/res/drawable/caption_more_button.xml
new file mode 100644
index 0000000..447df43
--- /dev/null
+++ b/libs/WindowManager/Shell/res/drawable/caption_more_button.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="32.0dp"
+ android:height="32.0dp"
+ android:viewportWidth="32.0"
+ android:viewportHeight="32.0"
+>
+ <group android:scaleX="0.5"
+ android:scaleY="0.5"
+ android:translateX="6.0"
+ android:translateY="6.0">
+ <path
+ android:fillColor="@android:color/black"
+ android:pathData="M8.083,22.833Q6.917,22.833 6.104,22Q5.292,21.167 5.292,20Q5.292,18.833 6.125,18Q6.958,17.167 8.125,17.167Q9.292,17.167 10.125,18Q10.958,18.833 10.958,20Q10.958,21.167 10.125,22Q9.292,22.833 8.083,22.833ZM20,22.833Q18.833,22.833 18,22Q17.167,21.167 17.167,20Q17.167,18.833 18,18Q18.833,17.167 20,17.167Q21.167,17.167 22,18Q22.833,18.833 22.833,20Q22.833,21.167 22,22Q21.167,22.833 20,22.833ZM31.875,22.833Q30.708,22.833 29.875,22Q29.042,21.167 29.042,20Q29.042,18.833 29.875,18Q30.708,17.167 31.917,17.167Q33.083,17.167 33.896,18Q34.708,18.833 34.708,20Q34.708,21.167 33.875,22Q33.042,22.833 31.875,22.833Z"/>
+ </group>
+</vector>
diff --git a/libs/WindowManager/Shell/res/drawable/caption_split_screen_button.xml b/libs/WindowManager/Shell/res/drawable/caption_split_screen_button.xml
new file mode 100644
index 0000000..c334a54
--- /dev/null
+++ b/libs/WindowManager/Shell/res/drawable/caption_split_screen_button.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="32.0dp"
+ android:height="32.0dp"
+ android:viewportWidth="32.0"
+ android:viewportHeight="32.0"
+>
+ <group android:translateX="6.0"
+ android:translateY="8.0">
+ <path
+ android:fillColor="@android:color/black"
+ android:pathData="M18 14L13 14L13 2L18 2L18 14ZM20 14L20 2C20 0.9 19.1 -3.93402e-08 18 -8.74228e-08L13 -3.0598e-07C11.9 -3.54062e-07 11 0.9 11 2L11 14C11 15.1 11.9 16 13 16L18 16C19.1 16 20 15.1 20 14ZM7 14L2 14L2 2L7 2L7 14ZM9 14L9 2C9 0.9 8.1 -5.20166e-07 7 -5.68248e-07L2 -7.86805e-07C0.9 -8.34888e-07 -3.93403e-08 0.9 -8.74228e-08 2L-6.11959e-07 14C-6.60042e-07 15.1 0.9 16 2 16L7 16C8.1 16 9 15.1 9 14Z"/> </group>
+</vector>
diff --git a/libs/WindowManager/Shell/res/drawable/handle_menu_background.xml b/libs/WindowManager/Shell/res/drawable/handle_menu_background.xml
new file mode 100644
index 0000000..e307f00
--- /dev/null
+++ b/libs/WindowManager/Shell/res/drawable/handle_menu_background.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="210.0dp"
+ android:height="64.0dp"
+ android:tint="@color/decor_button_light_color"
+>
+ <group android:scaleX="0.5"
+ android:scaleY="0.5"
+ android:translateX="8.0"
+ android:translateY="8.0" >
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M18.3334 14L13.3334 14L13.3334 2L18.3334 2L18.3334 14ZM20.3334 14L20.3334 2C20.3334 0.9 19.4334 -3.93402e-08 18.3334 -8.74228e-08L13.3334 -3.0598e-07C12.2334 -3.54062e-07 11.3334 0.9 11.3334 2L11.3334 14C11.3334 15.1 12.2334 16 13.3334 16L18.3334 16C19.4334 16 20.3334 15.1 20.3334 14ZM7.33337 14L2.33337 14L2.33337 2L7.33337 2L7.33337 14ZM9.33337 14L9.33337 2C9.33337 0.899999 8.43337 -5.20166e-07 7.33337 -5.68248e-07L2.33337 -7.86805e-07C1.23337 -8.34888e-07 0.333374 0.899999 0.333374 2L0.333373 14C0.333373 15.1 1.23337 16 2.33337 16L7.33337 16C8.43337 16 9.33337 15.1 9.33337 14Z"/>
+ </group>
+</vector>
diff --git a/libs/WindowManager/Shell/res/layout/caption_handle_menu.xml b/libs/WindowManager/Shell/res/layout/caption_handle_menu.xml
new file mode 100644
index 0000000..d9a140b
--- /dev/null
+++ b/libs/WindowManager/Shell/res/layout/caption_handle_menu.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="utf-8"?>
+ <!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<com.android.wm.shell.windowdecor.WindowDecorLinearLayout
+xmlns:android="http://schemas.android.com/apk/res/android"
+android:id="@+id/handle_menu"
+android:layout_width="wrap_content"
+android:layout_height="wrap_content"
+android:gravity="center_horizontal"
+android:background="@drawable/decor_caption_title">
+ <Button
+ style="@style/CaptionButtonStyle"
+ android:id="@+id/fullscreen_button"
+ android:contentDescription="@string/fullscreen_text"
+ android:background="@drawable/caption_fullscreen_button"/>
+ <Button
+ style="@style/CaptionButtonStyle"
+ android:id="@+id/split_screen_button"
+ android:contentDescription="@string/split_screen_text"
+ android:background="@drawable/caption_split_screen_button"/>
+ <Button
+ style="@style/CaptionButtonStyle"
+ android:id="@+id/floating_button"
+ android:contentDescription="@string/float_button_text"
+ android:background="@drawable/caption_floating_button"/>
+ <Button
+ style="@style/CaptionButtonStyle"
+ android:id="@+id/desktop_button"
+ android:contentDescription="@string/desktop_text"
+ android:background="@drawable/caption_desktop_button"/>
+ <Button
+ style="@style/CaptionButtonStyle"
+ android:id="@+id/more_button"
+ android:contentDescription="@string/more_button_text"
+ android:background="@drawable/caption_more_button"/>
+</com.android.wm.shell.windowdecor.WindowDecorLinearLayout>
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/layout/caption_window_decoration.xml b/libs/WindowManager/Shell/res/layout/caption_window_decoration.xml
index 38cd570..51e634c 100644
--- a/libs/WindowManager/Shell/res/layout/caption_window_decoration.xml
+++ b/libs/WindowManager/Shell/res/layout/caption_window_decoration.xml
@@ -19,14 +19,10 @@
android:id="@+id/caption"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:gravity="center_horizontal"
android:background="@drawable/decor_caption_title">
<Button
+ style="@style/CaptionButtonStyle"
android:id="@+id/back_button"
- android:layout_width="32dp"
- android:layout_height="32dp"
- android:layout_margin="5dp"
- android:padding="4dp"
android:contentDescription="@string/back_button_text"
android:background="@drawable/decor_back_button_dark"
/>
@@ -39,11 +35,8 @@
android:contentDescription="@string/handle_text"
android:background="@drawable/decor_handle_dark"/>
<Button
+ style="@style/CaptionButtonStyle"
android:id="@+id/close_window"
- android:layout_width="32dp"
- android:layout_height="32dp"
- android:layout_margin="5dp"
- android:padding="4dp"
android:contentDescription="@string/close_button_text"
android:background="@drawable/decor_close_button_dark"/>
</com.android.wm.shell.windowdecor.WindowDecorLinearLayout>
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/values/strings.xml b/libs/WindowManager/Shell/res/values/strings.xml
index 4807f08..097a567 100644
--- a/libs/WindowManager/Shell/res/values/strings.xml
+++ b/libs/WindowManager/Shell/res/values/strings.xml
@@ -202,4 +202,14 @@
<string name="back_button_text">Back</string>
<!-- Accessibility text for the caption handle [CHAR LIMIT=NONE] -->
<string name="handle_text">Handle</string>
+ <!-- Accessibility text for the handle fullscreen button [CHAR LIMIT=NONE] -->
+ <string name="fullscreen_text">Fullscreen</string>
+ <!-- Accessibility text for the handle desktop button [CHAR LIMIT=NONE] -->
+ <string name="desktop_text">Desktop Mode</string>
+ <!-- Accessibility text for the handle split screen button [CHAR LIMIT=NONE] -->
+ <string name="split_screen_text">Split Screen</string>
+ <!-- Accessibility text for the handle more options button [CHAR LIMIT=NONE] -->
+ <string name="more_button_text">More</string>
+ <!-- Accessibility text for the handle floating window button [CHAR LIMIT=NONE] -->
+ <string name="float_button_text">Float</string>
</resources>
diff --git a/libs/WindowManager/Shell/res/values/styles.xml b/libs/WindowManager/Shell/res/values/styles.xml
index 19f7c3e..a859721 100644
--- a/libs/WindowManager/Shell/res/values/styles.xml
+++ b/libs/WindowManager/Shell/res/values/styles.xml
@@ -30,6 +30,13 @@
<item name="android:activityCloseExitAnimation">@anim/forced_resizable_exit</item>
</style>
+ <style name="CaptionButtonStyle">
+ <item name="android:layout_width">32dp</item>
+ <item name="android:layout_height">32dp</item>
+ <item name="android:layout_margin">5dp</item>
+ <item name="android:padding">4dp</item>
+ </style>
+
<style name="DockedDividerBackground">
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">@dimen/split_divider_bar_width</item>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
index c2ad1a9..5b7d141 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
@@ -69,6 +69,7 @@
import com.android.wm.shell.common.split.SplitScreenConstants.SplitPosition;
import java.io.PrintWriter;
+import java.util.function.Consumer;
/**
* Records and handles layout of splits. Helps to calculate proper bounds when configuration or
@@ -599,7 +600,7 @@
/** Swich both surface position with animation. */
public void splitSwitching(SurfaceControl.Transaction t, SurfaceControl leash1,
- SurfaceControl leash2, Runnable finishCallback) {
+ SurfaceControl leash2, Consumer<Rect> finishCallback) {
final boolean isLandscape = isLandscape();
final Rect insets = getDisplayInsets(mContext);
insets.set(isLandscape ? insets.left : 0, isLandscape ? 0 : insets.top,
@@ -617,18 +618,13 @@
distBounds1.offset(-mRootBounds.left, -mRootBounds.top);
distBounds2.offset(-mRootBounds.left, -mRootBounds.top);
distDividerBounds.offset(-mRootBounds.left, -mRootBounds.top);
- // DO NOT move to insets area for smooth animation.
- distBounds1.set(distBounds1.left, distBounds1.top,
- distBounds1.right - insets.right, distBounds1.bottom - insets.bottom);
- distBounds2.set(distBounds2.left + insets.left, distBounds2.top + insets.top,
- distBounds2.right, distBounds2.bottom);
ValueAnimator animator1 = moveSurface(t, leash1, getRefBounds1(), distBounds1,
- false /* alignStart */);
+ -insets.left, -insets.top);
ValueAnimator animator2 = moveSurface(t, leash2, getRefBounds2(), distBounds2,
- true /* alignStart */);
+ insets.left, insets.top);
ValueAnimator animator3 = moveSurface(t, getDividerLeash(), getRefDividerBounds(),
- distDividerBounds, true /* alignStart */);
+ distDividerBounds, 0 /* offsetX */, 0 /* offsetY */);
AnimatorSet set = new AnimatorSet();
set.playTogether(animator1, animator2, animator3);
@@ -638,14 +634,14 @@
public void onAnimationEnd(Animator animation) {
mDividePosition = dividerPos;
updateBounds(mDividePosition);
- finishCallback.run();
+ finishCallback.accept(insets);
}
});
set.start();
}
private ValueAnimator moveSurface(SurfaceControl.Transaction t, SurfaceControl leash,
- Rect start, Rect end, boolean alignStart) {
+ Rect start, Rect end, float offsetX, float offsetY) {
Rect tempStart = new Rect(start);
Rect tempEnd = new Rect(end);
final float diffX = tempEnd.left - tempStart.left;
@@ -661,15 +657,15 @@
final float distY = tempStart.top + scale * diffY;
final int width = (int) (tempStart.width() + scale * diffWidth);
final int height = (int) (tempStart.height() + scale * diffHeight);
- if (alignStart) {
+ if (offsetX == 0 && offsetY == 0) {
t.setPosition(leash, distX, distY);
t.setWindowCrop(leash, width, height);
} else {
- final int offsetX = width - tempStart.width();
- final int offsetY = height - tempStart.height();
- t.setPosition(leash, distX + offsetX, distY + offsetY);
+ final int diffOffsetX = (int) (scale * offsetX);
+ final int diffOffsetY = (int) (scale * offsetY);
+ t.setPosition(leash, distX + diffOffsetX, distY + diffOffsetY);
mTempRect.set(0, 0, width, height);
- mTempRect.offsetTo(-offsetX, -offsetY);
+ mTempRect.offsetTo(-diffOffsetX, -diffOffsetY);
t.setCrop(leash, mTempRect);
}
t.apply();
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 2b36b4c..85bad17 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
@@ -335,6 +335,7 @@
final ActivityManager.RunningTaskInfo taskInfo = mPipOrganizer.getTaskInfo();
if (taskInfo != null) {
startExpandAnimation(taskInfo, mPipOrganizer.getSurfaceControl(),
+ mPipBoundsState.getBounds(), mPipBoundsState.getBounds(),
new Rect(mExitDestinationBounds), Surface.ROTATION_0);
}
mExitDestinationBounds.setEmpty();
@@ -475,6 +476,20 @@
taskInfo);
return;
}
+
+ // When exiting PiP, the PiP leash may be an Activity of a multi-windowing Task, for which
+ // case it may not be in the screen coordinate.
+ // Reparent the pip leash to the root with max layer so that we can animate it outside of
+ // parent crop, and make sure it is not covered by other windows.
+ final SurfaceControl pipLeash = pipChange.getLeash();
+ startTransaction.reparent(pipLeash, info.getRootLeash());
+ startTransaction.setLayer(pipLeash, Integer.MAX_VALUE);
+ // Note: because of this, the bounds to animate should be translated to the root coordinate.
+ final Point offset = info.getRootOffset();
+ final Rect currentBounds = mPipBoundsState.getBounds();
+ currentBounds.offset(-offset.x, -offset.y);
+ startTransaction.setPosition(pipLeash, currentBounds.left, currentBounds.top);
+
mFinishCallback = (wct, wctCB) -> {
mPipOrganizer.onExitPipFinished(taskInfo);
finishCallback.onTransitionFinished(wct, wctCB);
@@ -496,18 +511,17 @@
if (displayRotationChange != null) {
// Exiting PIP to fullscreen with orientation change.
startExpandAndRotationAnimation(info, startTransaction, finishTransaction,
- displayRotationChange, taskInfo, pipChange);
+ displayRotationChange, taskInfo, pipChange, offset);
return;
}
}
// Set the initial frame as scaling the end to the start.
final Rect destinationBounds = new Rect(pipChange.getEndAbsBounds());
- final Point offset = pipChange.getEndRelOffset();
destinationBounds.offset(-offset.x, -offset.y);
- startTransaction.setWindowCrop(pipChange.getLeash(), destinationBounds);
- mSurfaceTransactionHelper.scale(startTransaction, pipChange.getLeash(),
- destinationBounds, mPipBoundsState.getBounds());
+ startTransaction.setWindowCrop(pipLeash, destinationBounds);
+ mSurfaceTransactionHelper.scale(startTransaction, pipLeash, destinationBounds,
+ currentBounds);
startTransaction.apply();
// Check if it is fixed rotation.
@@ -532,19 +546,21 @@
y = destinationBounds.bottom;
}
mSurfaceTransactionHelper.rotateAndScaleWithCrop(finishTransaction,
- pipChange.getLeash(), endBounds, endBounds, new Rect(), degree, x, y,
+ pipLeash, endBounds, endBounds, new Rect(), degree, x, y,
true /* isExpanding */, rotationDelta == ROTATION_270 /* clockwise */);
} else {
rotationDelta = Surface.ROTATION_0;
}
- startExpandAnimation(taskInfo, pipChange.getLeash(), destinationBounds, rotationDelta);
+ startExpandAnimation(taskInfo, pipLeash, currentBounds, currentBounds, destinationBounds,
+ rotationDelta);
}
private void startExpandAndRotationAnimation(@NonNull TransitionInfo info,
@NonNull SurfaceControl.Transaction startTransaction,
@NonNull SurfaceControl.Transaction finishTransaction,
@NonNull TransitionInfo.Change displayRotationChange,
- @NonNull TaskInfo taskInfo, @NonNull TransitionInfo.Change pipChange) {
+ @NonNull TaskInfo taskInfo, @NonNull TransitionInfo.Change pipChange,
+ @NonNull Point offset) {
final int rotateDelta = deltaRotation(displayRotationChange.getStartRotation(),
displayRotationChange.getEndRotation());
@@ -556,7 +572,6 @@
final Rect startBounds = new Rect(pipChange.getStartAbsBounds());
rotateBounds(startBounds, displayRotationChange.getStartAbsBounds(), rotateDelta);
final Rect endBounds = new Rect(pipChange.getEndAbsBounds());
- final Point offset = pipChange.getEndRelOffset();
startBounds.offset(-offset.x, -offset.y);
endBounds.offset(-offset.x, -offset.y);
@@ -592,11 +607,12 @@
}
private void startExpandAnimation(final TaskInfo taskInfo, final SurfaceControl leash,
- final Rect destinationBounds, final int rotationDelta) {
+ final Rect baseBounds, final Rect startBounds, final Rect endBounds,
+ final int rotationDelta) {
final PipAnimationController.PipTransitionAnimator animator =
- mPipAnimationController.getAnimator(taskInfo, leash, mPipBoundsState.getBounds(),
- mPipBoundsState.getBounds(), destinationBounds, null,
- TRANSITION_DIRECTION_LEAVE_PIP, 0 /* startingAngle */, rotationDelta);
+ mPipAnimationController.getAnimator(taskInfo, leash, baseBounds, startBounds,
+ endBounds, null /* sourceHintRect */, TRANSITION_DIRECTION_LEAVE_PIP,
+ 0 /* startingAngle */, rotationDelta);
animator.setTransitionDirection(TRANSITION_DIRECTION_LEAVE_PIP)
.setPipAnimationCallback(mPipAnimationCallback)
.setDuration(mEnterExitAnimationDuration)
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index 943419b..15a1133 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -115,6 +115,7 @@
import com.android.wm.shell.common.DisplayImeController;
import com.android.wm.shell.common.DisplayInsetsController;
import com.android.wm.shell.common.DisplayLayout;
+import com.android.wm.shell.common.ScreenshotUtils;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.TransactionPool;
@@ -846,15 +847,44 @@
void setSideStagePositionAnimated(@SplitPosition int sideStagePosition) {
if (mSideStagePosition == sideStagePosition) return;
SurfaceControl.Transaction t = mTransactionPool.acquire();
+ mTempRect1.setEmpty();
final StageTaskListener topLeftStage =
mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT ? mSideStage : mMainStage;
+ final SurfaceControl topLeftScreenshot = ScreenshotUtils.takeScreenshot(t,
+ topLeftStage.mRootLeash, mTempRect1, Integer.MAX_VALUE - 1);
final StageTaskListener bottomRightStage =
mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT ? mMainStage : mSideStage;
+ final SurfaceControl bottomRightScreenshot = ScreenshotUtils.takeScreenshot(t,
+ bottomRightStage.mRootLeash, mTempRect1, Integer.MAX_VALUE - 1);
mSplitLayout.splitSwitching(t, topLeftStage.mRootLeash, bottomRightStage.mRootLeash,
- () -> {
- setSideStagePosition(SplitLayout.reversePosition(mSideStagePosition),
- null /* wct */);
- mTransactionPool.release(t);
+ insets -> {
+ WindowContainerTransaction wct = new WindowContainerTransaction();
+ setSideStagePosition(SplitLayout.reversePosition(mSideStagePosition), wct);
+ mSyncQueue.queue(wct);
+ mSyncQueue.runInSync(st -> {
+ updateSurfaceBounds(mSplitLayout, st, false /* applyResizingOffset */);
+ st.setPosition(topLeftScreenshot, -insets.left, -insets.top);
+ st.setPosition(bottomRightScreenshot, insets.left, insets.top);
+
+ final ValueAnimator va = ValueAnimator.ofFloat(1, 0);
+ va.addUpdateListener(valueAnimator-> {
+ final float progress = (float) valueAnimator.getAnimatedValue();
+ t.setAlpha(topLeftScreenshot, progress);
+ t.setAlpha(bottomRightScreenshot, progress);
+ t.apply();
+ });
+ va.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(
+ @androidx.annotation.NonNull Animator animation) {
+ t.remove(topLeftScreenshot);
+ t.remove(bottomRightScreenshot);
+ t.apply();
+ mTransactionPool.release(t);
+ }
+ });
+ va.start();
+ });
});
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
index af79386..928e71f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
@@ -46,6 +46,7 @@
import static android.window.TransitionInfo.FLAG_DISPLAY_HAS_ALERT_WINDOWS;
import static android.window.TransitionInfo.FLAG_FILLS_TASK;
import static android.window.TransitionInfo.FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY;
+import static android.window.TransitionInfo.FLAG_IS_BEHIND_STARTING_WINDOW;
import static android.window.TransitionInfo.FLAG_IS_DISPLAY;
import static android.window.TransitionInfo.FLAG_IS_VOICE_INTERACTION;
import static android.window.TransitionInfo.FLAG_IS_WALLPAPER;
@@ -319,6 +320,17 @@
final int wallpaperTransit = getWallpaperTransitType(info);
for (int i = info.getChanges().size() - 1; i >= 0; --i) {
final TransitionInfo.Change change = info.getChanges().get(i);
+ if (change.hasAllFlags(FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY
+ | FLAG_IS_BEHIND_STARTING_WINDOW)) {
+ // Don't animate embedded activity if it is covered by the starting window.
+ // Non-embedded case still needs animation because the container can still animate
+ // the starting window together, e.g. CLOSE or CHANGE type.
+ continue;
+ }
+ if (change.hasFlags(TransitionInfo.FLAGS_IS_NON_APP_WINDOW)) {
+ // Wallpaper, IME, and system windows don't need any default animations.
+ continue;
+ }
final boolean isTask = change.getTaskInfo() != null;
boolean isSeamlessDisplayChange = false;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
index 63d31cd..89205a6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
@@ -341,6 +341,15 @@
final SurfaceControl leash = change.getLeash();
final int mode = info.getChanges().get(i).getMode();
+ if (mode == TRANSIT_TO_FRONT
+ && ((change.getStartAbsBounds().height() != change.getEndAbsBounds().height()
+ || change.getStartAbsBounds().width() != change.getEndAbsBounds().width()))) {
+ // When the window is moved to front with a different size, make sure the crop is
+ // updated to prevent it from using the old crop.
+ t.setWindowCrop(leash, change.getEndAbsBounds().width(),
+ change.getEndAbsBounds().height());
+ }
+
// Don't move anything that isn't independent within its parents
if (!TransitionInfo.isIndependent(change, info)) {
if (mode == TRANSIT_OPEN || mode == TRANSIT_TO_FRONT || mode == TRANSIT_CHANGE) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java
index dca516a..36dd8ed 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java
@@ -26,11 +26,16 @@
import android.content.Context;
import android.hardware.input.InputManager;
import android.os.Handler;
+import android.os.Looper;
import android.os.SystemClock;
import android.util.Log;
import android.util.SparseArray;
import android.view.Choreographer;
+import android.view.InputChannel;
import android.view.InputDevice;
+import android.view.InputEvent;
+import android.view.InputEventReceiver;
+import android.view.InputMonitor;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
import android.view.MotionEvent;
@@ -64,8 +69,11 @@
private final SyncTransactionQueue mSyncQueue;
private FreeformTaskTransitionStarter mTransitionStarter;
private DesktopModeController mDesktopModeController;
+ private EventReceiver mEventReceiver;
+ private InputMonitor mInputMonitor;
private final SparseArray<CaptionWindowDecoration> mWindowDecorByTaskId = new SparseArray<>();
+ private final DragStartListenerImpl mDragStartListener = new DragStartListenerImpl();
public CaptionWindowDecorViewModel(
Context context,
@@ -108,12 +116,19 @@
mSyncQueue);
mWindowDecorByTaskId.put(taskInfo.taskId, windowDecoration);
- TaskPositioner taskPositioner = new TaskPositioner(mTaskOrganizer, windowDecoration);
+ TaskPositioner taskPositioner = new TaskPositioner(mTaskOrganizer, windowDecoration,
+ mDragStartListener);
CaptionTouchEventListener touchEventListener =
new CaptionTouchEventListener(taskInfo, taskPositioner);
windowDecoration.setCaptionListeners(touchEventListener, touchEventListener);
windowDecoration.setDragResizeCallback(taskPositioner);
setupWindowDecorationForTransition(taskInfo, startT, finishT);
+ if (mInputMonitor == null) {
+ mInputMonitor = InputManager.getInstance().monitorGestureInput(
+ "caption-touch", mContext.getDisplayId());
+ mEventReceiver = new EventReceiver(
+ mInputMonitor.getInputChannel(), Looper.myLooper());
+ }
return true;
}
@@ -165,6 +180,7 @@
@Override
public void onClick(View v) {
+ CaptionWindowDecoration decoration = mWindowDecorByTaskId.get(mTaskId);
final int id = v.getId();
if (id == R.id.close_window) {
WindowContainerTransaction wct = new WindowContainerTransaction();
@@ -176,6 +192,15 @@
}
} else if (id == R.id.back_button) {
injectBackKey();
+ } else if (id == R.id.caption_handle) {
+ decoration.createHandleMenu();
+ } else if (id == R.id.desktop_button) {
+ mDesktopModeController.setDesktopModeActive(true);
+ decoration.closeHandleMenu();
+ } else if (id == R.id.fullscreen_button) {
+ mDesktopModeController.setDesktopModeActive(false);
+ decoration.closeHandleMenu();
+ decoration.setButtonVisibility();
}
}
private void injectBackKey() {
@@ -257,6 +282,36 @@
}
}
+ // InputEventReceiver to listen for touch input outside of caption bounds
+ private class EventReceiver extends InputEventReceiver {
+ EventReceiver(InputChannel channel, Looper looper) {
+ super(channel, looper);
+ }
+
+ @Override
+ public void onInputEvent(InputEvent event) {
+ boolean handled = false;
+ if (event instanceof MotionEvent
+ && ((MotionEvent) event).getActionMasked() == MotionEvent.ACTION_UP) {
+ handled = true;
+ CaptionWindowDecorViewModel.this.handleMotionEvent((MotionEvent) event);
+ }
+ finishInputEvent(event, handled);
+ }
+ }
+
+ // If any input received is outside of caption bounds, turn off handle menu
+ private void handleMotionEvent(MotionEvent ev) {
+ int size = mWindowDecorByTaskId.size();
+ for (int i = 0; i < size; i++) {
+ CaptionWindowDecoration decoration = mWindowDecorByTaskId.valueAt(i);
+ if (decoration != null) {
+ decoration.closeHandleMenuIfNeeded(ev);
+ }
+ }
+ }
+
+
private boolean shouldShowWindowDecor(RunningTaskInfo taskInfo) {
if (taskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM) return true;
return DesktopModeStatus.IS_SUPPORTED
@@ -264,4 +319,11 @@
&& mDisplayController.getDisplayContext(taskInfo.displayId)
.getResources().getConfiguration().smallestScreenWidthDp >= 600;
}
+
+ private class DragStartListenerImpl implements TaskPositioner.DragStartListener{
+ @Override
+ public void onDragStart(int taskId) {
+ mWindowDecorByTaskId.get(taskId).closeHandleMenu();
+ }
+ }
}
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 9d61c14..03cad04 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
@@ -20,10 +20,14 @@
import android.app.WindowConfiguration;
import android.content.Context;
import android.content.res.ColorStateList;
+import android.content.res.Resources;
import android.graphics.Color;
+import android.graphics.Point;
+import android.graphics.Rect;
import android.graphics.drawable.VectorDrawable;
import android.os.Handler;
import android.view.Choreographer;
+import android.view.MotionEvent;
import android.view.SurfaceControl;
import android.view.View;
import android.view.ViewConfiguration;
@@ -58,6 +62,8 @@
private boolean mDesktopActive;
+ private AdditionalWindow mHandleMenu;
+
CaptionWindowDecoration(
Context context,
DisplayController displayController,
@@ -123,7 +129,20 @@
if (isDragResizeable) {
mRelayoutParams.setOutsets(outsetLeftId, outsetTopId, outsetRightId, outsetBottomId);
}
+ final Resources resources = mDecorWindowContext.getResources();
+ final Rect taskBounds = taskInfo.configuration.windowConfiguration.getBounds();
+ final int captionHeight = loadDimensionPixelSize(resources,
+ mRelayoutParams.mCaptionHeightId);
+ final int captionWidth = loadDimensionPixelSize(resources,
+ mRelayoutParams.mCaptionWidthId);
+ final int captionLeft = taskBounds.width() / 2
+ - captionWidth / 2;
+ final int captionTop = taskBounds.top
+ <= captionHeight / 2 ? 0 : -captionHeight / 2;
+ mRelayoutParams.setCaptionPosition(captionLeft, captionTop);
+
relayout(mRelayoutParams, startT, finishT, wct, oldRootView, mResult);
+ taskInfo = null; // Clear it just in case we use it accidentally
mTaskOrganizer.applyTransaction(wct);
@@ -137,15 +156,14 @@
}
// If this task is not focused, do not show caption.
- setCaptionVisibility(taskInfo.isFocused);
+ setCaptionVisibility(mTaskInfo.isFocused);
// Only handle should show if Desktop Mode is inactive.
boolean desktopCurrentStatus = DesktopModeStatus.isActive(mContext);
- if (mDesktopActive != desktopCurrentStatus && taskInfo.isFocused) {
+ if (mDesktopActive != desktopCurrentStatus && mTaskInfo.isFocused) {
mDesktopActive = desktopCurrentStatus;
setButtonVisibility();
}
- taskInfo = null; // Clear it just in case we use it accidentally
if (!isDragResizeable) {
closeDragResizeListener();
@@ -184,9 +202,22 @@
back.setOnClickListener(mOnCaptionButtonClickListener);
View handle = caption.findViewById(R.id.caption_handle);
handle.setOnTouchListener(mOnCaptionTouchListener);
+ handle.setOnClickListener(mOnCaptionButtonClickListener);
setButtonVisibility();
}
+ private void setupHandleMenu() {
+ View menu = mHandleMenu.mWindowViewHost.getView();
+ View fullscreen = menu.findViewById(R.id.fullscreen_button);
+ fullscreen.setOnClickListener(mOnCaptionButtonClickListener);
+ View desktop = menu.findViewById(R.id.desktop_button);
+ desktop.setOnClickListener(mOnCaptionButtonClickListener);
+ View split = menu.findViewById(R.id.split_screen_button);
+ split.setOnClickListener(mOnCaptionButtonClickListener);
+ View more = menu.findViewById(R.id.more_button);
+ more.setOnClickListener(mOnCaptionButtonClickListener);
+ }
+
/**
* Sets caption visibility based on task focus.
*
@@ -194,8 +225,9 @@
*/
private void setCaptionVisibility(boolean visible) {
int v = visible ? View.VISIBLE : View.GONE;
- View caption = mResult.mRootView.findViewById(R.id.caption);
- caption.setVisibility(v);
+ View captionView = mResult.mRootView.findViewById(R.id.caption);
+ captionView.setVisibility(v);
+ if (!visible) closeHandleMenu();
}
/**
@@ -203,6 +235,7 @@
*
*/
public void setButtonVisibility() {
+ mDesktopActive = DesktopModeStatus.isActive(mContext);
int v = mDesktopActive ? View.VISIBLE : View.GONE;
View caption = mResult.mRootView.findViewById(R.id.caption);
View back = caption.findViewById(R.id.back_button);
@@ -220,6 +253,10 @@
caption.getBackground().setTint(v == View.VISIBLE ? Color.WHITE : Color.TRANSPARENT);
}
+ public boolean isHandleMenuActive() {
+ return mHandleMenu != null;
+ }
+
private void closeDragResizeListener() {
if (mDragResizeListener == null) {
return;
@@ -228,9 +265,67 @@
mDragResizeListener = null;
}
+ /**
+ * Create and display handle menu window
+ */
+ public void createHandleMenu() {
+ SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+ final Resources resources = mDecorWindowContext.getResources();
+ int x = mRelayoutParams.mCaptionX;
+ int y = mRelayoutParams.mCaptionY;
+ int width = loadDimensionPixelSize(resources, mRelayoutParams.mCaptionWidthId);
+ int height = loadDimensionPixelSize(resources, mRelayoutParams.mCaptionHeightId);
+ String namePrefix = "Caption Menu";
+ mHandleMenu = addWindow(R.layout.caption_handle_menu, namePrefix, t,
+ x - mResult.mDecorContainerOffsetX, y - mResult.mDecorContainerOffsetY,
+ width, height);
+ mSyncQueue.runInSync(transaction -> {
+ transaction.merge(t);
+ t.close();
+ });
+ setupHandleMenu();
+ }
+
+ /**
+ * Close the handle menu window
+ */
+ public void closeHandleMenu() {
+ if (!isHandleMenuActive()) return;
+ mHandleMenu.releaseView();
+ mHandleMenu = null;
+ }
+
+ @Override
+ void releaseViews() {
+ closeHandleMenu();
+ super.releaseViews();
+ }
+
+ /**
+ * Close an open handle menu if input is outside of menu coordinates
+ * @param ev the tapped point to compare against
+ * @return
+ */
+ public void closeHandleMenuIfNeeded(MotionEvent ev) {
+ if (mHandleMenu != null) {
+ Point positionInParent = mTaskOrganizer.getRunningTaskInfo(mTaskInfo.taskId)
+ .positionInParent;
+ final Resources resources = mDecorWindowContext.getResources();
+ ev.offsetLocation(-mRelayoutParams.mCaptionX, -mRelayoutParams.mCaptionY);
+ ev.offsetLocation(-positionInParent.x, -positionInParent.y);
+ int width = loadDimensionPixelSize(resources, mRelayoutParams.mCaptionWidthId);
+ int height = loadDimensionPixelSize(resources, mRelayoutParams.mCaptionHeightId);
+ if (!(ev.getX() >= 0 && ev.getY() >= 0
+ && ev.getX() <= width && ev.getY() <= height)) {
+ closeHandleMenu();
+ }
+ }
+ }
+
@Override
public void close() {
closeDragResizeListener();
+ closeHandleMenu();
super.close();
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/TaskPositioner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/TaskPositioner.java
index 27c1011..f0f2db7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/TaskPositioner.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/TaskPositioner.java
@@ -42,14 +42,18 @@
private final Rect mResizeTaskBounds = new Rect();
private int mCtrlType;
+ private DragStartListener mDragStartListener;
- TaskPositioner(ShellTaskOrganizer taskOrganizer, WindowDecoration windowDecoration) {
+ TaskPositioner(ShellTaskOrganizer taskOrganizer, WindowDecoration windowDecoration,
+ DragStartListener dragStartListener) {
mTaskOrganizer = taskOrganizer;
mWindowDecoration = windowDecoration;
+ mDragStartListener = dragStartListener;
}
@Override
public void onDragResizeStart(int ctrlType, float x, float y) {
+ mDragStartListener.onDragStart(mWindowDecoration.mTaskInfo.taskId);
mCtrlType = ctrlType;
mTaskBoundsAtDragStart.set(
@@ -97,4 +101,12 @@
mTaskOrganizer.applyTransaction(wct);
}
}
+
+ interface DragStartListener {
+ /**
+ * Inform the implementing class that a drag resize has started
+ * @param taskId id of this positioner's {@link WindowDecoration}
+ */
+ void onDragStart(int taskId);
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
index b314163..7ecb3f3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
@@ -200,16 +200,17 @@
final Rect taskBounds = taskConfig.windowConfiguration.getBounds();
final Resources resources = mDecorWindowContext.getResources();
- final int decorContainerOffsetX = -loadDimensionPixelSize(resources, params.mOutsetLeftId);
- final int decorContainerOffsetY = -loadDimensionPixelSize(resources, params.mOutsetTopId);
+ outResult.mDecorContainerOffsetX = -loadDimensionPixelSize(resources, params.mOutsetLeftId);
+ outResult.mDecorContainerOffsetY = -loadDimensionPixelSize(resources, params.mOutsetTopId);
outResult.mWidth = taskBounds.width()
+ loadDimensionPixelSize(resources, params.mOutsetRightId)
- - decorContainerOffsetX;
+ - outResult.mDecorContainerOffsetX;
outResult.mHeight = taskBounds.height()
+ loadDimensionPixelSize(resources, params.mOutsetBottomId)
- - decorContainerOffsetY;
+ - outResult.mDecorContainerOffsetY;
startT.setPosition(
- mDecorationContainerSurface, decorContainerOffsetX, decorContainerOffsetY)
+ mDecorationContainerSurface,
+ outResult.mDecorContainerOffsetX, outResult.mDecorContainerOffsetY)
.setWindowCrop(mDecorationContainerSurface,
outResult.mWidth, outResult.mHeight)
// TODO(b/244455401): Change the z-order when it's better organized
@@ -252,14 +253,11 @@
final int captionHeight = loadDimensionPixelSize(resources, params.mCaptionHeightId);
final int captionWidth = loadDimensionPixelSize(resources, params.mCaptionWidthId);
- //Prevent caption from going offscreen if task is too high up
- final int captionYPos = taskBounds.top <= captionHeight / 2 ? 0 : captionHeight / 2;
-
startT.setPosition(
- mCaptionContainerSurface, -decorContainerOffsetX
- + taskBounds.width() / 2 - captionWidth / 2,
- -decorContainerOffsetY - captionYPos)
- .setWindowCrop(mCaptionContainerSurface, taskBounds.width(), captionHeight)
+ mCaptionContainerSurface,
+ -outResult.mDecorContainerOffsetX + params.mCaptionX,
+ -outResult.mDecorContainerOffsetY + params.mCaptionY)
+ .setWindowCrop(mCaptionContainerSurface, captionWidth, captionHeight)
.show(mCaptionContainerSurface);
if (mCaptionWindowManager == null) {
@@ -292,7 +290,7 @@
// Caption insets
mCaptionInsetsRect.set(taskBounds);
mCaptionInsetsRect.bottom =
- mCaptionInsetsRect.top + captionHeight - captionYPos;
+ mCaptionInsetsRect.top + captionHeight + params.mCaptionY;
wct.addRectInsetsProvider(mTaskInfo.token, mCaptionInsetsRect,
CAPTION_INSETS_TYPES);
} else {
@@ -302,10 +300,10 @@
// Task surface itself
Point taskPosition = mTaskInfo.positionInParent;
mTaskSurfaceCrop.set(
- decorContainerOffsetX,
- decorContainerOffsetY,
- outResult.mWidth + decorContainerOffsetX,
- outResult.mHeight + decorContainerOffsetY);
+ outResult.mDecorContainerOffsetX,
+ outResult.mDecorContainerOffsetY,
+ outResult.mWidth + outResult.mDecorContainerOffsetX,
+ outResult.mHeight + outResult.mDecorContainerOffsetY);
startT.show(mTaskSurface);
finishT.setPosition(mTaskSurface, taskPosition.x, taskPosition.y)
.setCrop(mTaskSurface, mTaskSurfaceCrop);
@@ -326,7 +324,7 @@
return true;
}
- private void releaseViews() {
+ void releaseViews() {
if (mViewHost != null) {
mViewHost.release();
mViewHost = null;
@@ -369,20 +367,60 @@
releaseViews();
}
- private static int loadDimensionPixelSize(Resources resources, int resourceId) {
+ static int loadDimensionPixelSize(Resources resources, int resourceId) {
if (resourceId == Resources.ID_NULL) {
return 0;
}
return resources.getDimensionPixelSize(resourceId);
}
- private static float loadDimension(Resources resources, int resourceId) {
+ static float loadDimension(Resources resources, int resourceId) {
if (resourceId == Resources.ID_NULL) {
return 0;
}
return resources.getDimension(resourceId);
}
+ /**
+ * Create a window associated with this WindowDecoration.
+ * Note that subclass must dispose of this when the task is hidden/closed.
+ * @param layoutId layout to make the window from
+ * @param t the transaction to apply
+ * @param xPos x position of new window
+ * @param yPos y position of new window
+ * @param width width of new window
+ * @param height height of new window
+ * @return
+ */
+ AdditionalWindow addWindow(int layoutId, String namePrefix,
+ SurfaceControl.Transaction t, int xPos, int yPos, int width, int height) {
+ final SurfaceControl.Builder builder = mSurfaceControlBuilderSupplier.get();
+ SurfaceControl windowSurfaceControl = builder
+ .setName(namePrefix + " of Task=" + mTaskInfo.taskId)
+ .setContainerLayer()
+ .setParent(mDecorationContainerSurface)
+ .build();
+ View v = LayoutInflater.from(mDecorWindowContext).inflate(layoutId, null);
+
+ t.setPosition(
+ windowSurfaceControl, xPos, yPos)
+ .setWindowCrop(windowSurfaceControl, width, height)
+ .show(windowSurfaceControl);
+ final WindowManager.LayoutParams lp =
+ new WindowManager.LayoutParams(width, height,
+ WindowManager.LayoutParams.TYPE_APPLICATION,
+ WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, PixelFormat.TRANSPARENT);
+ lp.setTitle("Additional window of Task=" + mTaskInfo.taskId);
+ lp.setTrustedOverlay();
+ WindowlessWindowManager windowManager = new WindowlessWindowManager(mTaskInfo.configuration,
+ windowSurfaceControl, null /* hostInputToken */);
+ SurfaceControlViewHost viewHost = mSurfaceControlViewHostFactory
+ .create(mDecorWindowContext, mDisplay, windowManager);
+ viewHost.setView(v, lp);
+ return new AdditionalWindow(windowSurfaceControl, viewHost,
+ mSurfaceControlTransactionSupplier);
+ }
+
static class RelayoutParams{
RunningTaskInfo mRunningTaskInfo;
int mLayoutResId;
@@ -395,6 +433,9 @@
int mOutsetLeftId;
int mOutsetRightId;
+ int mCaptionX;
+ int mCaptionY;
+
void setOutsets(int leftId, int topId, int rightId, int bottomId) {
mOutsetLeftId = leftId;
mOutsetTopId = topId;
@@ -402,6 +443,11 @@
mOutsetBottomId = bottomId;
}
+ void setCaptionPosition(int left, int top) {
+ mCaptionX = left;
+ mCaptionY = top;
+ }
+
void reset() {
mLayoutResId = Resources.ID_NULL;
mCaptionHeightId = Resources.ID_NULL;
@@ -412,6 +458,9 @@
mOutsetBottomId = Resources.ID_NULL;
mOutsetLeftId = Resources.ID_NULL;
mOutsetRightId = Resources.ID_NULL;
+
+ mCaptionX = 0;
+ mCaptionY = 0;
}
}
@@ -419,10 +468,14 @@
int mWidth;
int mHeight;
T mRootView;
+ int mDecorContainerOffsetX;
+ int mDecorContainerOffsetY;
void reset() {
mWidth = 0;
mHeight = 0;
+ mDecorContainerOffsetX = 0;
+ mDecorContainerOffsetY = 0;
mRootView = null;
}
}
@@ -432,4 +485,41 @@
return new SurfaceControlViewHost(c, d, wmm);
}
}
+
+ /**
+ * Subclass for additional windows associated with this WindowDecoration
+ */
+ static class AdditionalWindow {
+ SurfaceControl mWindowSurface;
+ SurfaceControlViewHost mWindowViewHost;
+ Supplier<SurfaceControl.Transaction> mTransactionSupplier;
+
+ private AdditionalWindow(SurfaceControl surfaceControl,
+ SurfaceControlViewHost surfaceControlViewHost,
+ Supplier<SurfaceControl.Transaction> transactionSupplier) {
+ mWindowSurface = surfaceControl;
+ mWindowViewHost = surfaceControlViewHost;
+ mTransactionSupplier = transactionSupplier;
+ }
+
+ void releaseView() {
+ WindowlessWindowManager windowManager = mWindowViewHost.getWindowlessWM();
+
+ if (mWindowViewHost != null) {
+ mWindowViewHost.release();
+ mWindowViewHost = null;
+ }
+ windowManager = null;
+ final SurfaceControl.Transaction t = mTransactionSupplier.get();
+ boolean released = false;
+ if (mWindowSurface != null) {
+ t.remove(mWindowSurface);
+ mWindowSurface = null;
+ released = true;
+ }
+ if (released) {
+ t.apply();
+ }
+ }
+ }
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonConstants.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonConstants.kt
index 7997892..651d935 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonConstants.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonConstants.kt
@@ -21,6 +21,7 @@
import com.android.server.wm.traces.common.ComponentNameMatcher
const val SYSTEM_UI_PACKAGE_NAME = "com.android.systemui"
+const val LAUNCHER_UI_PACKAGE_NAME = "com.google.android.apps.nexuslauncher"
val APP_PAIR_SPLIT_DIVIDER_COMPONENT = ComponentNameMatcher("", "AppPairSplitDivider#")
val DOCKED_STACK_DIVIDER_COMPONENT = ComponentNameMatcher("", "DockedStackDivider#")
val SPLIT_SCREEN_DIVIDER_COMPONENT = ComponentNameMatcher("", "StageCoordinatorSplitDivider#")
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt
index f802539..7546a55 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt
@@ -80,7 +80,7 @@
transitions { tapl.goHome() }
}
- @FlakyTest
+ @FlakyTest(bugId = 256863309)
@Test
override fun pipLayerReduces() {
testSpec.assertLayers {
@@ -108,14 +108,6 @@
}
}
- @FlakyTest(bugId = 239807171)
- @Test
- override fun pipAppLayerAlwaysVisible() = super.pipAppLayerAlwaysVisible()
-
- @FlakyTest(bugId = 239807171)
- @Test
- override fun pipLayerRemainInsideVisibleBounds() = super.pipLayerRemainInsideVisibleBounds()
-
@Presubmit
@Test
override fun focusChanges() {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/CopyContentInSplit.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/CopyContentInSplit.kt
index 9e76575..2bce8e45 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/CopyContentInSplit.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/CopyContentInSplit.kt
@@ -53,7 +53,7 @@
override val transition: FlickerBuilder.() -> Unit
get() = {
super.transition(this)
- setup { SplitScreenUtils.enterSplit(wmHelper, tapl, primaryApp, textEditApp) }
+ setup { SplitScreenUtils.enterSplit(wmHelper, tapl, device, primaryApp, textEditApp) }
transitions {
SplitScreenUtils.copyContentInSplit(
instrumentation,
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByDivider.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByDivider.kt
index 45eae2e..4757498 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByDivider.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByDivider.kt
@@ -55,7 +55,7 @@
get() = {
super.transition(this)
setup {
- SplitScreenUtils.enterSplit(wmHelper, tapl, primaryApp, secondaryApp)
+ SplitScreenUtils.enterSplit(wmHelper, tapl, device, primaryApp, secondaryApp)
}
transitions {
if (tapl.isTablet) {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByGoHome.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByGoHome.kt
index 6cfbb47..1d61955 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByGoHome.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByGoHome.kt
@@ -52,7 +52,7 @@
get() = {
super.transition(this)
setup {
- SplitScreenUtils.enterSplit(wmHelper, tapl, primaryApp, secondaryApp)
+ SplitScreenUtils.enterSplit(wmHelper, tapl, device, primaryApp, secondaryApp)
}
transitions {
tapl.goHome()
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DragDividerToResize.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DragDividerToResize.kt
index a80c88a..8d771fe 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DragDividerToResize.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DragDividerToResize.kt
@@ -56,7 +56,7 @@
get() = {
super.transition(this)
setup {
- SplitScreenUtils.enterSplit(wmHelper, tapl, primaryApp, secondaryApp)
+ SplitScreenUtils.enterSplit(wmHelper, tapl, device, primaryApp, secondaryApp)
}
transitions {
SplitScreenUtils.dragDividerToResizeAndWait(device, wmHelper)
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenFromOverview.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenFromOverview.kt
index 936afa9..fb7b8b7 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenFromOverview.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenFromOverview.kt
@@ -34,7 +34,6 @@
import com.android.wm.shell.flicker.splitScreenDividerBecomesVisible
import com.android.wm.shell.flicker.splitScreenEntered
import org.junit.Assume
-import org.junit.Before
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -55,7 +54,6 @@
get() = {
super.transition(this)
setup {
- tapl.workspace.switchToOverview().dismissAllTasks()
primaryApp.launchViaIntent(wmHelper)
secondaryApp.launchViaIntent(wmHelper)
tapl.goHome()
@@ -65,7 +63,7 @@
.waitForAndVerify()
}
transitions {
- SplitScreenUtils.splitFromOverview(tapl)
+ SplitScreenUtils.splitFromOverview(tapl, device)
SplitScreenUtils.waitForSplitComplete(wmHelper, primaryApp, secondaryApp)
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenBase.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenBase.kt
index e6d6379..c841333 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenBase.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenBase.kt
@@ -34,6 +34,7 @@
tapl.setEnableRotation(true)
setRotation(testSpec.startRotation)
tapl.setExpectedRotation(testSpec.startRotation)
+ tapl.workspace.switchToOverview().dismissAllTasks()
}
teardown {
primaryApp.exit(wmHelper)
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenUtils.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenUtils.kt
index 6453ed8..ead451f 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenUtils.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenUtils.kt
@@ -25,6 +25,7 @@
import androidx.test.uiautomator.By
import androidx.test.uiautomator.BySelector
import androidx.test.uiautomator.UiDevice
+import androidx.test.uiautomator.UiObject2
import androidx.test.uiautomator.Until
import com.android.launcher3.tapl.LauncherInstrumentation
import com.android.server.wm.flicker.helpers.ImeAppHelper
@@ -38,13 +39,16 @@
import com.android.server.wm.traces.common.IComponentNameMatcher
import com.android.server.wm.traces.parser.toFlickerComponent
import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
+import com.android.wm.shell.flicker.LAUNCHER_UI_PACKAGE_NAME
import com.android.wm.shell.flicker.SYSTEM_UI_PACKAGE_NAME
+import java.util.Collections
internal object SplitScreenUtils {
private const val TIMEOUT_MS = 3_000L
private const val DRAG_DURATION_MS = 1_000L
private const val NOTIFICATION_SCROLLER = "notification_stack_scroller"
private const val DIVIDER_BAR = "docked_divider_handle"
+ private const val OVERVIEW_SNAPSHOT = "snapshot"
private const val GESTURE_STEP_MS = 16L
private const val LONG_PRESS_TIME_MS = 100L
private val SPLIT_DECOR_MANAGER = ComponentNameMatcher("", "SplitDecorManager#")
@@ -55,6 +59,8 @@
get() = By.text("Flicker Test Notification")
private val dividerBarSelector: BySelector
get() = By.res(SYSTEM_UI_PACKAGE_NAME, DIVIDER_BAR)
+ private val overviewSnapshotSelector: BySelector
+ get() = By.res(LAUNCHER_UI_PACKAGE_NAME, OVERVIEW_SNAPSHOT)
fun getPrimary(instrumentation: Instrumentation): StandardAppHelper =
SimpleAppHelper(
@@ -94,24 +100,39 @@
fun enterSplit(
wmHelper: WindowManagerStateHelper,
tapl: LauncherInstrumentation,
+ device: UiDevice,
primaryApp: StandardAppHelper,
secondaryApp: StandardAppHelper
) {
- tapl.workspace.switchToOverview().dismissAllTasks()
primaryApp.launchViaIntent(wmHelper)
secondaryApp.launchViaIntent(wmHelper)
tapl.goHome()
wmHelper.StateSyncBuilder().withHomeActivityVisible().waitForAndVerify()
- splitFromOverview(tapl)
+ splitFromOverview(tapl, device)
waitForSplitComplete(wmHelper, primaryApp, secondaryApp)
}
- fun splitFromOverview(tapl: LauncherInstrumentation) {
+ fun splitFromOverview(tapl: LauncherInstrumentation, device: UiDevice) {
// Note: The initial split position in landscape is different between tablet and phone.
// In landscape, tablet will let the first app split to right side, and phone will
// split to left side.
if (tapl.isTablet) {
- tapl.workspace.switchToOverview().overviewActions.clickSplit().currentTask.open()
+ // TAPL's currentTask on tablet is sometimes not what we expected if the overview
+ // contains more than 3 task views. We need to use uiautomator directly to find the
+ // second task to split.
+ tapl.workspace.switchToOverview().overviewActions.clickSplit()
+ val snapshots = device.wait(Until.findObjects(overviewSnapshotSelector), TIMEOUT_MS)
+ if (snapshots == null || snapshots.size < 1) {
+ error("Fail to find a overview snapshot to split.")
+ }
+
+ // Find the second task in the upper right corner in split select mode by sorting
+ // 'left' in descending order and 'top' in ascending order.
+ Collections.sort(snapshots, { t1: UiObject2, t2: UiObject2 ->
+ t2.getVisibleBounds().left - t1.getVisibleBounds().left})
+ Collections.sort(snapshots, { t1: UiObject2, t2: UiObject2 ->
+ t1.getVisibleBounds().top - t2.getVisibleBounds().top})
+ snapshots[0].click()
} else {
tapl.workspace
.switchToOverview()
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchAppByDoubleTapDivider.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchAppByDoubleTapDivider.kt
index 73159c9..f7610c4 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchAppByDoubleTapDivider.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchAppByDoubleTapDivider.kt
@@ -56,7 +56,7 @@
get() = {
super.transition(this)
setup {
- SplitScreenUtils.enterSplit(wmHelper, tapl, primaryApp, secondaryApp)
+ SplitScreenUtils.enterSplit(wmHelper, tapl, device, primaryApp, secondaryApp)
}
transitions {
SplitScreenUtils.doubleTapDividerToSwitch(device)
@@ -145,15 +145,19 @@
// robust enough to get the correct end state.
}
+ @Presubmit
@Test
fun splitScreenDividerKeepVisible() = testSpec.layerKeepVisible(SPLIT_SCREEN_DIVIDER_COMPONENT)
+ @Presubmit
@Test
fun primaryAppLayerIsVisibleAtEnd() = testSpec.layerIsVisibleAtEnd(primaryApp)
+ @Presubmit
@Test
fun secondaryAppLayerIsVisibleAtEnd() = testSpec.layerIsVisibleAtEnd(secondaryApp)
+ @Presubmit
@Test
fun primaryAppBoundsIsVisibleAtEnd() = testSpec.splitAppLayerBoundsIsVisibleAtEnd(
primaryApp,
@@ -161,6 +165,7 @@
portraitPosTop = true
)
+ @Presubmit
@Test
fun secondaryAppBoundsIsVisibleAtEnd() = testSpec.splitAppLayerBoundsIsVisibleAtEnd(
secondaryApp,
@@ -168,9 +173,11 @@
portraitPosTop = false
)
+ @Presubmit
@Test
fun primaryAppWindowIsVisibleAtEnd() = testSpec.appWindowIsVisibleAtEnd(primaryApp)
+ @Presubmit
@Test
fun secondaryAppWindowIsVisibleAtEnd() = testSpec.appWindowIsVisibleAtEnd(secondaryApp)
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromAnotherApp.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromAnotherApp.kt
index 553840c..993dba2 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromAnotherApp.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromAnotherApp.kt
@@ -52,7 +52,7 @@
get() = {
super.transition(this)
setup {
- SplitScreenUtils.enterSplit(wmHelper, tapl, primaryApp, secondaryApp)
+ SplitScreenUtils.enterSplit(wmHelper, tapl, device, primaryApp, secondaryApp)
thirdApp.launchViaIntent(wmHelper)
wmHelper.StateSyncBuilder().withWindowSurfaceAppeared(thirdApp).waitForAndVerify()
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromHome.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromHome.kt
index 1f117d0..2a552cd 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromHome.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromHome.kt
@@ -51,7 +51,7 @@
get() = {
super.transition(this)
setup {
- SplitScreenUtils.enterSplit(wmHelper, tapl, primaryApp, secondaryApp)
+ SplitScreenUtils.enterSplit(wmHelper, tapl, device, primaryApp, secondaryApp)
tapl.goHome()
wmHelper.StateSyncBuilder().withHomeActivityVisible().waitForAndVerify()
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromRecent.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromRecent.kt
index d7b3ec2..7f81bae 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromRecent.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromRecent.kt
@@ -51,7 +51,7 @@
get() = {
super.transition(this)
setup {
- SplitScreenUtils.enterSplit(wmHelper, tapl, primaryApp, secondaryApp)
+ SplitScreenUtils.enterSplit(wmHelper, tapl, device, primaryApp, secondaryApp)
tapl.goHome()
wmHelper.StateSyncBuilder().withHomeActivityVisible().waitForAndVerify()
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBetweenSplitPairs.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBetweenSplitPairs.kt
new file mode 100644
index 0000000..d84954d
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBetweenSplitPairs.kt
@@ -0,0 +1,248 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.splitscreen
+
+import android.platform.test.annotations.FlakyTest
+import android.platform.test.annotations.Postsubmit
+import android.platform.test.annotations.Presubmit
+import androidx.test.filters.RequiresDevice
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.wm.shell.flicker.SPLIT_SCREEN_DIVIDER_COMPONENT
+import com.android.wm.shell.flicker.appWindowBecomesInvisible
+import com.android.wm.shell.flicker.appWindowBecomesVisible
+import com.android.wm.shell.flicker.appWindowIsInvisibleAtEnd
+import com.android.wm.shell.flicker.appWindowIsVisibleAtStart
+import com.android.wm.shell.flicker.appWindowIsVisibleAtEnd
+import com.android.wm.shell.flicker.layerBecomesInvisible
+import com.android.wm.shell.flicker.layerBecomesVisible
+import com.android.wm.shell.flicker.splitAppLayerBoundsIsVisibleAtEnd
+import com.android.wm.shell.flicker.splitAppLayerBoundsSnapToDivider
+import com.android.wm.shell.flicker.splitScreenDividerIsVisibleAtStart
+import com.android.wm.shell.flicker.splitScreenDividerIsVisibleAtEnd
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test quick switch between two split pairs.
+ *
+ * To run this test: `atest WMShellFlickerTests:SwitchBetweenSplitPairs`
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+class SwitchBetweenSplitPairs(testSpec: FlickerTestParameter) : SplitScreenBase(testSpec) {
+ private val thirdApp = SplitScreenUtils.getIme(instrumentation)
+ private val fourthApp = SplitScreenUtils.getSendNotification(instrumentation)
+
+ override val transition: FlickerBuilder.() -> Unit
+ get() = {
+ super.transition(this)
+ setup {
+ SplitScreenUtils.enterSplit(wmHelper, tapl, device, primaryApp, secondaryApp)
+ SplitScreenUtils.enterSplit(wmHelper, tapl, device, thirdApp, fourthApp)
+ SplitScreenUtils.waitForSplitComplete(wmHelper, thirdApp, fourthApp)
+ }
+ transitions {
+ tapl.launchedAppState.quickSwitchToPreviousApp()
+ SplitScreenUtils.waitForSplitComplete(wmHelper, primaryApp, secondaryApp)
+ }
+ teardown {
+ thirdApp.exit(wmHelper)
+ fourthApp.exit(wmHelper)
+ }
+ }
+
+ @Postsubmit
+ @Test
+ fun cujCompleted() {
+ testSpec.appWindowIsVisibleAtStart(thirdApp)
+ testSpec.appWindowIsVisibleAtStart(fourthApp)
+ testSpec.splitScreenDividerIsVisibleAtStart()
+
+ testSpec.appWindowIsVisibleAtEnd(primaryApp)
+ testSpec.appWindowIsVisibleAtEnd(secondaryApp)
+ testSpec.appWindowIsInvisibleAtEnd(thirdApp)
+ testSpec.appWindowIsInvisibleAtEnd(fourthApp)
+ testSpec.splitScreenDividerIsVisibleAtEnd()
+ }
+
+ @Postsubmit
+ @Test
+ fun splitScreenDividerInvisibleAtMiddle() =
+ testSpec.assertLayers {
+ this.isVisible(SPLIT_SCREEN_DIVIDER_COMPONENT)
+ .then()
+ .isInvisible(SPLIT_SCREEN_DIVIDER_COMPONENT)
+ .then()
+ .isVisible(SPLIT_SCREEN_DIVIDER_COMPONENT)
+ }
+
+ @FlakyTest(bugId = 247095572)
+ @Test
+ fun primaryAppLayerBecomesVisible() = testSpec.layerBecomesVisible(primaryApp)
+
+ @FlakyTest(bugId = 247095572)
+ @Test
+ fun secondaryAppLayerBecomesVisible() = testSpec.layerBecomesVisible(secondaryApp)
+
+ @FlakyTest(bugId = 247095572)
+ @Test
+ fun thirdAppLayerBecomesInvisible() = testSpec.layerBecomesInvisible(thirdApp)
+
+ @FlakyTest(bugId = 247095572)
+ @Test
+ fun fourthAppLayerBecomesInvisible() = testSpec.layerBecomesInvisible(fourthApp)
+
+ @Postsubmit
+ @Test
+ fun primaryAppBoundsIsVisibleAtEnd() =
+ testSpec.splitAppLayerBoundsIsVisibleAtEnd(
+ primaryApp,
+ landscapePosLeft = tapl.isTablet,
+ portraitPosTop = false
+ )
+
+ @Postsubmit
+ @Test
+ fun secondaryAppBoundsIsVisibleAtEnd() =
+ testSpec.splitAppLayerBoundsIsVisibleAtEnd(
+ secondaryApp,
+ landscapePosLeft = !tapl.isTablet,
+ portraitPosTop = true
+ )
+
+ @Postsubmit
+ @Test
+ fun thirdAppBoundsIsVisibleAtBegin() =
+ testSpec.assertLayersStart {
+ this.splitAppLayerBoundsSnapToDivider(
+ thirdApp,
+ landscapePosLeft = tapl.isTablet,
+ portraitPosTop = false,
+ testSpec.startRotation
+ )
+ }
+
+ @Postsubmit
+ @Test
+ fun fourthAppBoundsIsVisibleAtBegin() =
+ testSpec.assertLayersStart {
+ this.splitAppLayerBoundsSnapToDivider(
+ fourthApp,
+ landscapePosLeft = !tapl.isTablet,
+ portraitPosTop = true,
+ testSpec.startRotation
+ )
+ }
+
+ @Postsubmit
+ @Test
+ fun primaryAppWindowBecomesVisible() = testSpec.appWindowBecomesVisible(primaryApp)
+
+ @Postsubmit
+ @Test
+ fun secondaryAppWindowBecomesVisible() = testSpec.appWindowBecomesVisible(secondaryApp)
+
+ @Postsubmit
+ @Test
+ fun thirdAppWindowBecomesVisible() = testSpec.appWindowBecomesInvisible(thirdApp)
+
+ @Postsubmit
+ @Test
+ fun fourthAppWindowBecomesVisible() = testSpec.appWindowBecomesInvisible(fourthApp)
+
+ /** {@inheritDoc} */
+ @FlakyTest(bugId = 251268711)
+ @Test
+ override fun entireScreenCovered() =
+ super.entireScreenCovered()
+
+ /** {@inheritDoc} */
+ @Presubmit
+ @Test
+ override fun navBarLayerIsVisibleAtStartAndEnd() =
+ super.navBarLayerIsVisibleAtStartAndEnd()
+
+ /** {@inheritDoc} */
+ @FlakyTest(bugId = 206753786)
+ @Test
+ override fun navBarLayerPositionAtStartAndEnd() =
+ super.navBarLayerPositionAtStartAndEnd()
+
+ /** {@inheritDoc} */
+ @Presubmit
+ @Test
+ override fun navBarWindowIsAlwaysVisible() =
+ super.navBarWindowIsAlwaysVisible()
+
+ /** {@inheritDoc} */
+ @Presubmit
+ @Test
+ override fun statusBarLayerIsVisibleAtStartAndEnd() =
+ super.statusBarLayerIsVisibleAtStartAndEnd()
+
+ /** {@inheritDoc} */
+ @Presubmit
+ @Test
+ override fun statusBarLayerPositionAtStartAndEnd() =
+ super.statusBarLayerPositionAtStartAndEnd()
+
+ /** {@inheritDoc} */
+ @Presubmit
+ @Test
+ override fun statusBarWindowIsAlwaysVisible() =
+ super.statusBarWindowIsAlwaysVisible()
+
+ /** {@inheritDoc} */
+ @Presubmit
+ @Test
+ override fun taskBarLayerIsVisibleAtStartAndEnd() =
+ super.taskBarLayerIsVisibleAtStartAndEnd()
+
+ /** {@inheritDoc} */
+ @Presubmit
+ @Test
+ override fun taskBarWindowIsAlwaysVisible() =
+ super.taskBarWindowIsAlwaysVisible()
+
+ /** {@inheritDoc} */
+ @FlakyTest
+ @Test
+ override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
+ super.visibleLayersShownMoreThanOneConsecutiveEntry()
+
+ /** {@inheritDoc} */
+ @Presubmit
+ @Test
+ override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
+ super.visibleWindowsShownMoreThanOneConsecutiveEntry()
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): List<FlickerTestParameter> {
+ return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests()
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitScreenControllerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitScreenControllerTests.java
index 55883ab..d01f3d3 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitScreenControllerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitScreenControllerTests.java
@@ -39,6 +39,7 @@
import android.content.Intent;
import android.content.pm.ActivityInfo;
+import androidx.test.annotation.UiThreadTest;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
@@ -110,6 +111,7 @@
}
@Test
+ @UiThreadTest
public void instantiateController_registerDumpCallback() {
doReturn(mMainExecutor).when(mTaskOrganizer).getExecutor();
when(mDisplayController.getDisplayLayout(anyInt())).thenReturn(new DisplayLayout());
@@ -118,6 +120,7 @@
}
@Test
+ @UiThreadTest
public void instantiateController_registerCommandCallback() {
doReturn(mMainExecutor).when(mTaskOrganizer).getExecutor();
when(mDisplayController.getDisplayLayout(anyInt())).thenReturn(new DisplayLayout());
@@ -126,6 +129,7 @@
}
@Test
+ @UiThreadTest
public void testControllerRegistersKeyguardChangeListener() {
doReturn(mMainExecutor).when(mTaskOrganizer).getExecutor();
when(mDisplayController.getDisplayLayout(anyInt())).thenReturn(new DisplayLayout());
@@ -134,6 +138,7 @@
}
@Test
+ @UiThreadTest
public void instantiateController_addExternalInterface() {
doReturn(mMainExecutor).when(mTaskOrganizer).getExecutor();
when(mDisplayController.getDisplayLayout(anyInt())).thenReturn(new DisplayLayout());
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
index 8350870..3569860 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
@@ -50,6 +50,7 @@
import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
+import androidx.test.annotation.UiThreadTest;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
@@ -113,6 +114,7 @@
private StageCoordinator mStageCoordinator;
@Before
+ @UiThreadTest
public void setup() {
MockitoAnnotations.initMocks(this);
mStageCoordinator = spy(new StageCoordinator(mContext, DEFAULT_DISPLAY, mSyncQueue,
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java
index 4d37e5d..15181b1 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java
@@ -35,6 +35,7 @@
import android.app.ActivityManager;
import android.content.Context;
+import android.content.res.Resources;
import android.graphics.Color;
import android.graphics.Point;
import android.graphics.Rect;
@@ -64,6 +65,7 @@
import org.mockito.ArgumentCaptor;
import org.mockito.InOrder;
import org.mockito.Mock;
+import org.mockito.Mockito;
import java.util.ArrayList;
import java.util.List;
@@ -102,12 +104,14 @@
private final List<SurfaceControl.Builder> mMockSurfaceControlBuilders = new ArrayList<>();
private SurfaceControl.Transaction mMockSurfaceControlStartT;
private SurfaceControl.Transaction mMockSurfaceControlFinishT;
+ private SurfaceControl.Transaction mMockSurfaceControlAddWindowT;
private WindowDecoration.RelayoutParams mRelayoutParams = new WindowDecoration.RelayoutParams();
@Before
public void setUp() {
mMockSurfaceControlStartT = createMockSurfaceControlTransaction();
mMockSurfaceControlFinishT = createMockSurfaceControlTransaction();
+ mMockSurfaceControlAddWindowT = createMockSurfaceControlTransaction();
doReturn(mMockSurfaceControlViewHost).when(mMockSurfaceControlViewHostFactory)
.create(any(), any(), any());
@@ -227,8 +231,8 @@
verify(captionContainerSurfaceBuilder).setParent(decorContainerSurface);
verify(captionContainerSurfaceBuilder).setContainerLayer();
- verify(mMockSurfaceControlStartT).setPosition(captionContainerSurface, -46, 8);
- verify(mMockSurfaceControlStartT).setWindowCrop(captionContainerSurface, 300, 64);
+ verify(mMockSurfaceControlStartT).setPosition(captionContainerSurface, 20, 40);
+ verify(mMockSurfaceControlStartT).setWindowCrop(captionContainerSurface, 432, 64);
verify(mMockSurfaceControlStartT).show(captionContainerSurface);
verify(mMockSurfaceControlViewHostFactory).create(any(), eq(defaultDisplay), any());
@@ -242,7 +246,7 @@
verify(mMockView).setTaskFocusState(true);
verify(mMockWindowContainerTransaction)
.addRectInsetsProvider(taskInfo.token,
- new Rect(100, 300, 400, 332),
+ new Rect(100, 300, 400, 364),
new int[] { InsetsState.ITYPE_CAPTION_BAR });
}
@@ -366,6 +370,71 @@
verify(mMockSurfaceControlViewHost).setView(same(mMockView), any());
}
+ @Test
+ public void testAddWindow() {
+ final Display defaultDisplay = mock(Display.class);
+ doReturn(defaultDisplay).when(mMockDisplayController)
+ .getDisplay(Display.DEFAULT_DISPLAY);
+
+ final SurfaceControl decorContainerSurface = mock(SurfaceControl.class);
+ final SurfaceControl.Builder decorContainerSurfaceBuilder =
+ createMockSurfaceControlBuilder(decorContainerSurface);
+ mMockSurfaceControlBuilders.add(decorContainerSurfaceBuilder);
+ final SurfaceControl taskBackgroundSurface = mock(SurfaceControl.class);
+ final SurfaceControl.Builder taskBackgroundSurfaceBuilder =
+ createMockSurfaceControlBuilder(taskBackgroundSurface);
+ mMockSurfaceControlBuilders.add(taskBackgroundSurfaceBuilder);
+ final SurfaceControl captionContainerSurface = mock(SurfaceControl.class);
+ final SurfaceControl.Builder captionContainerSurfaceBuilder =
+ createMockSurfaceControlBuilder(captionContainerSurface);
+ mMockSurfaceControlBuilders.add(captionContainerSurfaceBuilder);
+
+ final SurfaceControl.Transaction t = mock(SurfaceControl.Transaction.class);
+ mMockSurfaceControlTransactions.add(t);
+ final ActivityManager.TaskDescription.Builder taskDescriptionBuilder =
+ new ActivityManager.TaskDescription.Builder()
+ .setBackgroundColor(Color.YELLOW);
+ final ActivityManager.RunningTaskInfo taskInfo = new TestRunningTaskInfoBuilder()
+ .setDisplayId(Display.DEFAULT_DISPLAY)
+ .setTaskDescriptionBuilder(taskDescriptionBuilder)
+ .setBounds(TASK_BOUNDS)
+ .setPositionInParent(TASK_POSITION_IN_PARENT.x, TASK_POSITION_IN_PARENT.y)
+ .setVisible(true)
+ .build();
+ taskInfo.isFocused = true;
+ taskInfo.configuration.densityDpi = DisplayMetrics.DENSITY_DEFAULT * 2;
+ mRelayoutParams.setOutsets(
+ R.dimen.test_window_decor_left_outset,
+ R.dimen.test_window_decor_top_outset,
+ R.dimen.test_window_decor_right_outset,
+ R.dimen.test_window_decor_bottom_outset);
+ final SurfaceControl taskSurface = mock(SurfaceControl.class);
+ final TestWindowDecoration windowDecor = createWindowDecoration(taskInfo, taskSurface);
+ windowDecor.relayout(taskInfo);
+
+ final SurfaceControl additionalWindowSurface = mock(SurfaceControl.class);
+ final SurfaceControl.Builder additionalWindowSurfaceBuilder =
+ createMockSurfaceControlBuilder(additionalWindowSurface);
+ mMockSurfaceControlBuilders.add(additionalWindowSurfaceBuilder);
+
+ WindowDecoration.AdditionalWindow additionalWindow = windowDecor.addTestWindow();
+
+ verify(additionalWindowSurfaceBuilder).setContainerLayer();
+ verify(additionalWindowSurfaceBuilder).setParent(decorContainerSurface);
+ verify(additionalWindowSurfaceBuilder).build();
+ verify(mMockSurfaceControlAddWindowT).setPosition(additionalWindowSurface, 20, 40);
+ verify(mMockSurfaceControlAddWindowT).setWindowCrop(additionalWindowSurface, 432, 64);
+ verify(mMockSurfaceControlAddWindowT).show(additionalWindowSurface);
+ verify(mMockSurfaceControlViewHostFactory, Mockito.times(2))
+ .create(any(), eq(defaultDisplay), any());
+ assertThat(additionalWindow.mWindowViewHost).isNotNull();
+
+ additionalWindow.releaseView();
+
+ assertThat(additionalWindow.mWindowViewHost).isNull();
+ assertThat(additionalWindow.mWindowSurface).isNull();
+ }
+
private TestWindowDecoration createWindowDecoration(
ActivityManager.RunningTaskInfo taskInfo, SurfaceControl testSurface) {
return new TestWindowDecoration(InstrumentationRegistry.getInstrumentation().getContext(),
@@ -429,5 +498,20 @@
relayout(mRelayoutParams, mMockSurfaceControlStartT, mMockSurfaceControlFinishT,
mMockWindowContainerTransaction, mMockView, mRelayoutResult);
}
+
+ private WindowDecoration.AdditionalWindow addTestWindow() {
+ final Resources resources = mDecorWindowContext.getResources();
+ int x = mRelayoutParams.mCaptionX;
+ int y = mRelayoutParams.mCaptionY;
+ int width = loadDimensionPixelSize(resources, mRelayoutParams.mCaptionWidthId);
+ int height = loadDimensionPixelSize(resources, mRelayoutParams.mCaptionHeightId);
+ String name = "Test Window";
+ WindowDecoration.AdditionalWindow additionalWindow =
+ addWindow(R.layout.caption_handle_menu, name, mMockSurfaceControlAddWindowT,
+ x - mRelayoutResult.mDecorContainerOffsetX,
+ y - mRelayoutResult.mDecorContainerOffsetY,
+ width, height);
+ return additionalWindow;
+ }
}
}
diff --git a/libs/hwui/jni/android_graphics_Canvas.cpp b/libs/hwui/jni/android_graphics_Canvas.cpp
index 0513447..35258a3 100644
--- a/libs/hwui/jni/android_graphics_Canvas.cpp
+++ b/libs/hwui/jni/android_graphics_Canvas.cpp
@@ -20,6 +20,7 @@
#include <android/api-level.h>
#else
#define __ANDROID_API_P__ 28
+#define __ANDROID_API_U__ 34
#endif
#include <androidfw/ResourceTypes.h>
#include <hwui/Canvas.h>
@@ -30,8 +31,9 @@
#include <nativehelper/ScopedPrimitiveArray.h>
#include <nativehelper/ScopedStringChars.h>
-#include "FontUtils.h"
#include "Bitmap.h"
+#include "FontUtils.h"
+#include "SkAndroidFrameworkUtils.h"
#include "SkBitmap.h"
#include "SkBlendMode.h"
#include "SkClipOp.h"
@@ -42,10 +44,10 @@
#include "SkMatrix.h"
#include "SkPath.h"
#include "SkPoint.h"
+#include "SkRRect.h"
#include "SkRect.h"
#include "SkRefCnt.h"
#include "SkRegion.h"
-#include "SkRRect.h"
#include "SkScalar.h"
#include "SkVertices.h"
@@ -710,6 +712,9 @@
static void setCompatibilityVersion(JNIEnv* env, jobject, jint apiLevel) {
Canvas::setCompatibilityVersion(apiLevel);
+ if (apiLevel < __ANDROID_API_U__) {
+ SkAndroidFrameworkUtils::UseLegacyLocalMatrixConcatenation();
+ }
}
static void punchHole(JNIEnv* env, jobject, jlong canvasPtr, jfloat left, jfloat top, jfloat right,
@@ -800,7 +805,6 @@
ret |= RegisterMethodsOrDie(env, "android/graphics/BaseCanvas", gDrawMethods, NELEM(gDrawMethods));
ret |= RegisterMethodsOrDie(env, "android/graphics/BaseRecordingCanvas", gDrawMethods, NELEM(gDrawMethods));
return ret;
-
}
}; // namespace android
diff --git a/media/java/android/media/AudioPlaybackConfiguration.java b/media/java/android/media/AudioPlaybackConfiguration.java
index 819358b..60e3a306 100644
--- a/media/java/android/media/AudioPlaybackConfiguration.java
+++ b/media/java/android/media/AudioPlaybackConfiguration.java
@@ -569,6 +569,17 @@
}
}
+ private boolean isMuteAffectingActiveState() {
+ if (mMutedState == PLAYER_MUTE_INVALID) {
+ // mute state is not set, therefore it will not affect the active state
+ return false;
+ }
+
+ return (mMutedState & PLAYER_MUTE_CLIENT_VOLUME) != 0
+ || (mMutedState & PLAYER_MUTE_VOLUME_SHAPER) != 0
+ || (mMutedState & PLAYER_MUTE_PLAYBACK_RESTRICTED) != 0;
+ }
+
/**
* @hide
* Returns true if the player is considered "active", i.e. actively playing with unmuted
@@ -580,8 +591,7 @@
public boolean isActive() {
switch (mPlayerState) {
case PLAYER_STATE_STARTED:
- return mMutedState == 0
- || mMutedState == PLAYER_MUTE_INVALID; // only send true if not muted
+ return !isMuteAffectingActiveState();
case PLAYER_STATE_UNKNOWN:
case PLAYER_STATE_RELEASED:
case PLAYER_STATE_IDLE:
diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp
index 95599bd..1183ca3 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -174,6 +174,12 @@
jfieldID typeId;
} gDescriptorInfo;
+static struct {
+ jclass clazz;
+ jmethodID ctorId;
+ jmethodID setId;
+} gBufferInfo;
+
struct fields_t {
jmethodID postEventFromNativeID;
jmethodID lockAndGetContextID;
@@ -460,11 +466,7 @@
return err;
}
- ScopedLocalRef<jclass> clazz(
- env, env->FindClass("android/media/MediaCodec$BufferInfo"));
-
- jmethodID method = env->GetMethodID(clazz.get(), "set", "(IIJI)V");
- env->CallVoidMethod(bufferInfo, method, (jint)offset, (jint)size, timeUs, flags);
+ env->CallVoidMethod(bufferInfo, gBufferInfo.setId, (jint)offset, (jint)size, timeUs, flags);
return OK;
}
@@ -1091,13 +1093,7 @@
CHECK(msg->findInt64("timeUs", &timeUs));
CHECK(msg->findInt32("flags", (int32_t *)&flags));
- ScopedLocalRef<jclass> clazz(
- env, env->FindClass("android/media/MediaCodec$BufferInfo"));
- jmethodID ctor = env->GetMethodID(clazz.get(), "<init>", "()V");
- jmethodID method = env->GetMethodID(clazz.get(), "set", "(IIJI)V");
-
- obj = env->NewObject(clazz.get(), ctor);
-
+ obj = env->NewObject(gBufferInfo.clazz, gBufferInfo.ctorId);
if (obj == NULL) {
if (env->ExceptionCheck()) {
ALOGE("Could not create MediaCodec.BufferInfo.");
@@ -1107,7 +1103,7 @@
return;
}
- env->CallVoidMethod(obj, method, (jint)offset, (jint)size, timeUs, flags);
+ env->CallVoidMethod(obj, gBufferInfo.setId, (jint)offset, (jint)size, timeUs, flags);
break;
}
@@ -3235,6 +3231,16 @@
gDescriptorInfo.typeId = env->GetFieldID(clazz.get(), "mType", "I");
CHECK(gDescriptorInfo.typeId != NULL);
+
+ clazz.reset(env->FindClass("android/media/MediaCodec$BufferInfo"));
+ CHECK(clazz.get() != NULL);
+ gBufferInfo.clazz = (jclass)env->NewGlobalRef(clazz.get());
+
+ gBufferInfo.ctorId = env->GetMethodID(clazz.get(), "<init>", "()V");
+ CHECK(gBufferInfo.ctorId != NULL);
+
+ gBufferInfo.setId = env->GetMethodID(clazz.get(), "set", "(IIJI)V");
+ CHECK(gBufferInfo.setId != NULL);
}
static void android_media_MediaCodec_native_setup(
diff --git a/packages/CarrierDefaultApp/Android.bp b/packages/CarrierDefaultApp/Android.bp
index 6990ad0..62ffe38 100644
--- a/packages/CarrierDefaultApp/Android.bp
+++ b/packages/CarrierDefaultApp/Android.bp
@@ -13,4 +13,9 @@
libs: ["SliceStore"],
platform_apis: true,
certificate: "platform",
+ optimize: {
+ proguard_flags_files: [
+ "proguard.flags",
+ ],
+ },
}
diff --git a/packages/CarrierDefaultApp/assets/slice_store_test.html b/packages/CarrierDefaultApp/assets/slice_store_test.html
new file mode 100644
index 0000000..7ddbd2d
--- /dev/null
+++ b/packages/CarrierDefaultApp/assets/slice_store_test.html
@@ -0,0 +1,78 @@
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="UTF-8">
+ <meta name="description" content="
+ This is a HTML page that calls and verifies responses from the @JavascriptInterface functions of
+ SliceStoreWebInterface. Test SliceStore APIs using ADB shell commands and the APIs below:
+
+ FROM TERMINAL:
+ Allow device to override carrier configs:
+ $ adb root
+ Set PREMIUM_CAPABILITY_PRIORITIZE_LATENCY enabled:
+ $ adb shell cmd phone cc set-value -p supported_premium_capabilities_int_array 34
+ Set the carrier purchase URL to this test HTML file:
+ $ adb shell cmd phone cc set-value -p premium_capability_purchase_url_string \
+ file:///android_asset/slice_store_test.html
+ OPTIONAL: Allow premium capability purchase on LTE:
+ $ adb shell cmd phone cc set-value -p premium_capability_supported_on_lte_bool true
+ OPTIONAL: Override ServiceState to fake a NR SA connection:
+ $ adb shell am broadcast -a com.android.internal.telephony.TestServiceState --ei data_rat 20
+
+ FROM TEST ACTIVITY:
+ TelephonyManager tm = getApplicationContext().getSystemService(TelephonyManager.class)
+ tm.isPremiumCapabilityAvailable(TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY);
+ LinkedBlockingQueue<Integer> purchaseRequests = new LinkedBlockingQueue<>();
+ tm.purchasePremiumCapability(TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY,
+ this.getMainExecutor(), request::offer);
+
+ When the test application starts, this HTML will be loaded into the WebView along with the
+ associated JavaScript functions in file:///android_asset/slice_store_test.js.
+ Click on the buttons in the HTML to call the corresponding @JavascriptInterface APIs.
+
+ RESET DEVICE STATE:
+ Clear carrier configurations that were set:
+ $ adb shell cmd phone cc clear-values
+ Clear ServiceState override that was set:
+ $ adb shell am broadcast -a com.android.internal.telephony.TestServiceState --es action reset
+ ">
+ <title>Test SliceStoreActivity</title>
+ <script type="text/javascript" src="slice_store_test.js"></script>
+</head>
+<body>
+ <h1>Test SliceStoreActivity</h1>
+ <h2>Get requested premium capability</h2>
+ <button type="button" onclick="testGetRequestedCapability()">
+ Get requested premium capability
+ </button>
+ <p id="requested_capability"></p>
+
+ <h2>Notify purchase successful</h2>
+ <button type="button" onclick="testNotifyPurchaseSuccessful(60000)">
+ Notify purchase successful for 1 minute
+ </button>
+ <p id="purchase_successful"></p>
+
+ <h2>Notify purchase failed</h2>
+ <button type="button" onclick="testNotifyPurchaseFailed()">
+ Notify purchase failed
+ </button>
+ <p id="purchase_failed"></p>
+</body>
+</html>
diff --git a/packages/CarrierDefaultApp/assets/slice_store_test.js b/packages/CarrierDefaultApp/assets/slice_store_test.js
new file mode 100644
index 0000000..f12a6da
--- /dev/null
+++ b/packages/CarrierDefaultApp/assets/slice_store_test.js
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+function testGetRequestedCapability() {
+ let capability = SliceStoreWebInterface.getRequestedCapability();
+ document.getElementById("requested_capability").innerHTML =
+ "Premium capability requested: " + capability;
+}
+
+function testNotifyPurchaseSuccessful(duration_ms_long = 0) {
+ SliceStoreWebInterface.notifyPurchaseSuccessful(duration);
+ document.getElementById("purchase_successful").innerHTML =
+ "Notified purchase success for duration: " + duration;
+}
+
+function testNotifyPurchaseFailed() {
+ SliceStoreWebInterface.notifyPurchaseFailed();
+ document.getElementById("purchase_failed").innerHTML =
+ "Notified purchase failed.";
+}
diff --git a/packages/CarrierDefaultApp/proguard.flags b/packages/CarrierDefaultApp/proguard.flags
new file mode 100644
index 0000000..64fec2c
--- /dev/null
+++ b/packages/CarrierDefaultApp/proguard.flags
@@ -0,0 +1,4 @@
+# Keep classes and methods that have the @JavascriptInterface annotation
+-keepclassmembers class * {
+ @android.webkit.JavascriptInterface <methods>;
+}
diff --git a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/SliceStoreActivity.java b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/SliceStoreActivity.java
index 602e31c..348e389 100644
--- a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/SliceStoreActivity.java
+++ b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/SliceStoreActivity.java
@@ -20,47 +20,63 @@
import android.annotation.Nullable;
import android.app.Activity;
import android.app.NotificationManager;
+import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.telephony.CarrierConfigManager;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.util.Log;
+import android.view.KeyEvent;
import android.webkit.WebView;
import com.android.phone.slicestore.SliceStore;
import java.net.MalformedURLException;
import java.net.URL;
+import java.util.concurrent.TimeUnit;
/**
* Activity that launches when the user clicks on the network boost notification.
+ * This will open a {@link WebView} for the carrier website to allow the user to complete the
+ * premium capability purchase.
+ * The carrier website can get the requested premium capability using the JavaScript interface
+ * method {@code SliceStoreWebInterface.getRequestedCapability()}.
+ * If the purchase is successful, the carrier website shall notify SliceStore using the JavaScript
+ * interface method {@code SliceStoreWebInterface.notifyPurchaseSuccessful(duration)}, where
+ * {@code duration} is the duration of the network boost.
+ * If the purchase was not successful, the carrier website shall notify SliceStore using the
+ * JavaScript interface method {@code SliceStoreWebInterface.notifyPurchaseFailed()}.
+ * If either of these notification methods are not called, the purchase cannot be completed
+ * successfully and the purchase request will eventually time out.
*/
public class SliceStoreActivity extends Activity {
private static final String TAG = "SliceStoreActivity";
- private URL mUrl;
- private WebView mWebView;
- private int mPhoneId;
+ private @NonNull WebView mWebView;
+ private @NonNull Context mApplicationContext;
private int mSubId;
- private @TelephonyManager.PremiumCapability int mCapability;
+ @TelephonyManager.PremiumCapability protected int mCapability;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent intent = getIntent();
- mPhoneId = intent.getIntExtra(SliceStore.EXTRA_PHONE_ID,
- SubscriptionManager.INVALID_PHONE_INDEX);
mSubId = intent.getIntExtra(SliceStore.EXTRA_SUB_ID,
SubscriptionManager.INVALID_SUBSCRIPTION_ID);
mCapability = intent.getIntExtra(SliceStore.EXTRA_PREMIUM_CAPABILITY,
SliceStore.PREMIUM_CAPABILITY_INVALID);
- mUrl = getUrl();
- logd("onCreate: mPhoneId=" + mPhoneId + ", mSubId=" + mSubId + ", mCapability="
+ mApplicationContext = getApplicationContext();
+ URL url = getUrl();
+ logd("onCreate: subId=" + mSubId + ", capability="
+ TelephonyManager.convertPremiumCapabilityToString(mCapability)
- + ", mUrl=" + mUrl);
- getApplicationContext().getSystemService(NotificationManager.class)
+ + ", url=" + url);
+
+ // Cancel network boost notification
+ mApplicationContext.getSystemService(NotificationManager.class)
.cancel(SliceStoreBroadcastReceiver.NETWORK_BOOST_NOTIFICATION_TAG, mCapability);
+
+ // Verify intent and values are valid
if (!SliceStoreBroadcastReceiver.isIntentValid(intent)) {
loge("Not starting SliceStoreActivity with an invalid Intent: " + intent);
SliceStoreBroadcastReceiver.sendSliceStoreResponse(
@@ -68,10 +84,15 @@
finishAndRemoveTask();
return;
}
- if (mUrl == null) {
- loge("Unable to create a URL from carrier configs.");
- SliceStoreBroadcastReceiver.sendSliceStoreResponse(
- intent, SliceStore.EXTRA_INTENT_CARRIER_ERROR);
+ if (url == null) {
+ String error = "Unable to create a URL from carrier configs.";
+ loge(error);
+ Intent data = new Intent();
+ data.putExtra(SliceStore.EXTRA_FAILURE_CODE,
+ SliceStore.FAILURE_CODE_CARRIER_URL_UNAVAILABLE);
+ data.putExtra(SliceStore.EXTRA_FAILURE_REASON, error);
+ SliceStoreBroadcastReceiver.sendSliceStoreResponseWithData(
+ mApplicationContext, getIntent(), SliceStore.EXTRA_INTENT_CARRIER_ERROR, data);
finishAndRemoveTask();
return;
}
@@ -83,12 +104,53 @@
return;
}
+ // Create a reference to this activity in SliceStoreBroadcastReceiver
SliceStoreBroadcastReceiver.updateSliceStoreActivity(mCapability, this);
+ // Create and configure WebView
mWebView = new WebView(this);
+ // Enable JavaScript for the carrier purchase website to send results back to SliceStore
+ mWebView.getSettings().setJavaScriptEnabled(true);
+ mWebView.addJavascriptInterface(new SliceStoreWebInterface(this), "SliceStoreWebInterface");
+
+ // Display WebView
setContentView(mWebView);
- mWebView.loadUrl(mUrl.toString());
- // TODO(b/245882601): Get back response from WebView
+ mWebView.loadUrl(url.toString());
+ }
+
+ protected void onPurchaseSuccessful(long duration) {
+ logd("onPurchaseSuccessful: Carrier website indicated successfully purchased premium "
+ + "capability " + TelephonyManager.convertPremiumCapabilityToString(mCapability)
+ + " for " + TimeUnit.MILLISECONDS.toMinutes(duration) + " minutes.");
+ Intent intent = new Intent();
+ intent.putExtra(SliceStore.EXTRA_PURCHASE_DURATION, duration);
+ SliceStoreBroadcastReceiver.sendSliceStoreResponseWithData(
+ mApplicationContext, getIntent(), SliceStore.EXTRA_INTENT_SUCCESS, intent);
+ finishAndRemoveTask();
+ }
+
+ protected void onPurchaseFailed(@SliceStore.FailureCode int failureCode,
+ @Nullable String failureReason) {
+ logd("onPurchaseFailed: Carrier website indicated purchase failed for premium capability "
+ + TelephonyManager.convertPremiumCapabilityToString(mCapability) + " with code: "
+ + SliceStore.convertFailureCodeToString(failureCode) + " and reason: "
+ + failureReason);
+ Intent data = new Intent();
+ data.putExtra(SliceStore.EXTRA_FAILURE_CODE, failureCode);
+ data.putExtra(SliceStore.EXTRA_FAILURE_REASON, failureReason);
+ SliceStoreBroadcastReceiver.sendSliceStoreResponseWithData(
+ mApplicationContext, getIntent(), SliceStore.EXTRA_INTENT_CARRIER_ERROR, data);
+ finishAndRemoveTask();
+ }
+
+ @Override
+ public boolean onKeyDown(int keyCode, @NonNull KeyEvent event) {
+ // Pressing back in the WebView will go to the previous page instead of closing SliceStore.
+ if ((keyCode == KeyEvent.KEYCODE_BACK) && mWebView.canGoBack()) {
+ mWebView.goBack();
+ return true;
+ }
+ return super.onKeyDown(keyCode, event);
}
@Override
@@ -100,8 +162,8 @@
super.onDestroy();
}
- private @Nullable URL getUrl() {
- String url = getApplicationContext().getSystemService(CarrierConfigManager.class)
+ @Nullable private URL getUrl() {
+ String url = mApplicationContext.getSystemService(CarrierConfigManager.class)
.getConfigForSubId(mSubId).getString(
CarrierConfigManager.KEY_PREMIUM_CAPABILITY_PURCHASE_URL_STRING);
try {
diff --git a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/SliceStoreBroadcastReceiver.java b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/SliceStoreBroadcastReceiver.java
index 7eb851d..7867ef1 100644
--- a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/SliceStoreBroadcastReceiver.java
+++ b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/SliceStoreBroadcastReceiver.java
@@ -26,6 +26,7 @@
import android.content.Intent;
import android.graphics.drawable.Icon;
import android.os.UserHandle;
+import android.telephony.AnomalyReporter;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
@@ -37,6 +38,7 @@
import java.lang.ref.WeakReference;
import java.util.HashMap;
import java.util.Map;
+import java.util.UUID;
/**
* The SliceStoreBroadcastReceiver listens for {@link SliceStore#ACTION_START_SLICE_STORE} from the
@@ -47,6 +49,12 @@
public class SliceStoreBroadcastReceiver extends BroadcastReceiver{
private static final String TAG = "SliceStoreBroadcastReceiver";
+ /**
+ * UUID to report an anomaly when receiving a PendingIntent from an application or process
+ * other than the Phone process.
+ */
+ private static final String UUID_BAD_PENDING_INTENT = "c360246e-95dc-4abf-9dc1-929a76cd7e53";
+
/** Weak references to {@link SliceStoreActivity} for each capability, if it exists. */
private static final Map<Integer, WeakReference<SliceStoreActivity>> sSliceStoreActivities =
new HashMap<>();
@@ -102,6 +110,28 @@
}
/**
+ * Send the PendingIntent containing the corresponding SliceStore response with additional data.
+ *
+ * @param context The Context to use to send the PendingIntent.
+ * @param intent The Intent containing the PendingIntent extra.
+ * @param extra The extra to get the PendingIntent to send.
+ * @param data The Intent containing additional data to send with the PendingIntent.
+ */
+ public static void sendSliceStoreResponseWithData(@NonNull Context context,
+ @NonNull Intent intent, @NonNull String extra, @NonNull Intent data) {
+ PendingIntent pendingIntent = intent.getParcelableExtra(extra, PendingIntent.class);
+ if (pendingIntent == null) {
+ loge("PendingIntent does not exist for extra: " + extra);
+ return;
+ }
+ try {
+ pendingIntent.send(context, 0 /* unused */, data);
+ } catch (PendingIntent.CanceledException e) {
+ loge("Unable to send " + getPendingIntentType(extra) + " intent: " + e);
+ }
+ }
+
+ /**
* Check whether the Intent is valid and can be used to complete purchases in the SliceStore.
* This checks that all necessary extras exist and that the values are valid.
*
@@ -139,7 +169,8 @@
return isPendingIntentValid(intent, SliceStore.EXTRA_INTENT_CANCELED)
&& isPendingIntentValid(intent, SliceStore.EXTRA_INTENT_CARRIER_ERROR)
&& isPendingIntentValid(intent, SliceStore.EXTRA_INTENT_REQUEST_FAILED)
- && isPendingIntentValid(intent, SliceStore.EXTRA_INTENT_NOT_DEFAULT_DATA);
+ && isPendingIntentValid(intent, SliceStore.EXTRA_INTENT_NOT_DEFAULT_DATA)
+ && isPendingIntentValid(intent, SliceStore.EXTRA_INTENT_SUCCESS);
}
private static boolean isPendingIntentValid(@NonNull Intent intent, @NonNull String extra) {
@@ -148,12 +179,20 @@
if (pendingIntent == null) {
loge("isPendingIntentValid: " + intentType + " intent not found.");
return false;
- } else if (pendingIntent.getCreatorPackage().equals(TelephonyManager.PHONE_PROCESS_NAME)) {
- return true;
}
- loge("isPendingIntentValid: " + intentType + " intent was created by "
- + pendingIntent.getCreatorPackage() + " instead of the phone process.");
- return false;
+ String creatorPackage = pendingIntent.getCreatorPackage();
+ if (!creatorPackage.equals(TelephonyManager.PHONE_PROCESS_NAME)) {
+ String logStr = "isPendingIntentValid: " + intentType + " intent was created by "
+ + creatorPackage + " instead of the phone process.";
+ loge(logStr);
+ AnomalyReporter.reportAnomaly(UUID.fromString(UUID_BAD_PENDING_INTENT), logStr);
+ return false;
+ }
+ if (!pendingIntent.isBroadcast()) {
+ loge("isPendingIntentValid: " + intentType + " intent is not a broadcast.");
+ return false;
+ }
+ return true;
}
@NonNull private static String getPendingIntentType(@NonNull String extra) {
@@ -162,6 +201,7 @@
case SliceStore.EXTRA_INTENT_CARRIER_ERROR: return "carrier error";
case SliceStore.EXTRA_INTENT_REQUEST_FAILED: return "request failed";
case SliceStore.EXTRA_INTENT_NOT_DEFAULT_DATA: return "not default data";
+ case SliceStore.EXTRA_INTENT_SUCCESS: return "success";
default: {
loge("Unknown pending intent extra: " + extra);
return "unknown(" + extra + ")";
@@ -292,7 +332,6 @@
logd("Closing SliceStore WebView since the user did not complete the purchase "
+ "in time.");
sSliceStoreActivities.get(capability).get().finishAndRemoveTask();
- // TODO: Display a toast to indicate timeout for better UX?
}
}
diff --git a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/SliceStoreWebInterface.java b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/SliceStoreWebInterface.java
new file mode 100644
index 0000000..ab5d080
--- /dev/null
+++ b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/SliceStoreWebInterface.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.carrierdefaultapp;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.telephony.TelephonyManager;
+import android.webkit.JavascriptInterface;
+
+import com.android.phone.slicestore.SliceStore;
+
+/**
+ * SliceStore web interface class allowing carrier websites to send responses back to SliceStore
+ * using JavaScript.
+ */
+public class SliceStoreWebInterface {
+ @NonNull SliceStoreActivity mActivity;
+
+ public SliceStoreWebInterface(@NonNull SliceStoreActivity activity) {
+ mActivity = activity;
+ }
+ /**
+ * Interface method allowing the carrier website to get the premium capability
+ * that was requested to purchase.
+ *
+ * This can be called using the JavaScript below:
+ * <script type="text/javascript">
+ * function getRequestedCapability(duration) {
+ * SliceStoreWebInterface.getRequestedCapability();
+ * }
+ * </script>
+ */
+ @JavascriptInterface
+ @TelephonyManager.PremiumCapability public int getRequestedCapability() {
+ return mActivity.mCapability;
+ }
+
+ /**
+ * Interface method allowing the carrier website to notify the SliceStore of a successful
+ * premium capability purchase and the duration for which the premium capability is purchased.
+ *
+ * This can be called using the JavaScript below:
+ * <script type="text/javascript">
+ * function notifyPurchaseSuccessful(duration_ms_long = 0) {
+ * SliceStoreWebInterface.notifyPurchaseSuccessful(duration_ms_long);
+ * }
+ * </script>
+ *
+ * @param duration The duration for which the premium capability is purchased in milliseconds.
+ */
+ @JavascriptInterface
+ public void notifyPurchaseSuccessful(long duration) {
+ mActivity.onPurchaseSuccessful(duration);
+ }
+
+ /**
+ * Interface method allowing the carrier website to notify the SliceStore of a failed
+ * premium capability purchase.
+ *
+ * This can be called using the JavaScript below:
+ * <script type="text/javascript">
+ * function notifyPurchaseFailed() {
+ * SliceStoreWebInterface.notifyPurchaseFailed();
+ * }
+ * </script>
+ *
+ * @param failureCode The failure code.
+ * @param failureReason If the failure code is {@link SliceStore#FAILURE_CODE_UNKNOWN},
+ * the human-readable reason for failure.
+ */
+ @JavascriptInterface
+ public void notifyPurchaseFailed(@SliceStore.FailureCode int failureCode,
+ @Nullable String failureReason) {
+ mActivity.onPurchaseFailed(failureCode, failureReason);
+ }
+}
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt b/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt
index 56fb1a9..01348e4 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt
@@ -23,6 +23,8 @@
import android.credentials.CreateCredentialRequest
import android.credentials.ui.Constants
import android.credentials.ui.Entry
+import android.credentials.ui.CreateCredentialProviderData
+import android.credentials.ui.GetCredentialProviderData
import android.credentials.ui.ProviderData
import android.credentials.ui.RequestInfo
import android.credentials.ui.BaseDialogResult
@@ -36,7 +38,7 @@
import com.android.credentialmanager.createflow.RequestDisplayInfo
import com.android.credentialmanager.getflow.GetCredentialUiState
import com.android.credentialmanager.getflow.GetScreenState
-import com.android.credentialmanager.jetpack.CredentialEntryUi.Companion.TYPE_PUBLIC_KEY_CREDENTIAL
+import com.android.credentialmanager.jetpack.provider.CredentialEntryUi.Companion.TYPE_PUBLIC_KEY_CREDENTIAL
// Consider repo per screen, similar to view model?
class CredentialManagerRepo(
@@ -54,10 +56,22 @@
RequestInfo::class.java
) ?: testRequestInfo()
- providerList = intent.extras?.getParcelableArrayList(
- ProviderData.EXTRA_PROVIDER_DATA_LIST,
- ProviderData::class.java
- ) ?: testProviderList()
+ providerList = when (requestInfo.type) {
+ RequestInfo.TYPE_CREATE ->
+ intent.extras?.getParcelableArrayList(
+ ProviderData.EXTRA_ENABLED_PROVIDER_DATA_LIST,
+ CreateCredentialProviderData::class.java
+ ) ?: testCreateCredentialProviderList()
+ RequestInfo.TYPE_GET ->
+ intent.extras?.getParcelableArrayList(
+ ProviderData.EXTRA_ENABLED_PROVIDER_DATA_LIST,
+ GetCredentialProviderData::class.java
+ ) ?: testGetCredentialProviderList()
+ else -> {
+ // TODO: fail gracefully
+ throw IllegalStateException("Unrecognized request type: ${requestInfo.type}")
+ }
+ }
resultReceiver = intent.getParcelableExtra(
Constants.EXTRA_RESULT_RECEIVER,
@@ -84,7 +98,9 @@
}
fun getCredentialInitialUiState(): GetCredentialUiState {
- val providerList = GetFlowUtils.toProviderList(providerList, context)
+ val providerList = GetFlowUtils.toProviderList(
+ // TODO: handle runtime cast error
+ providerList as List<GetCredentialProviderData>, context)
// TODO: covert from real requestInfo
val requestDisplayInfo = com.android.credentialmanager.getflow.RequestDisplayInfo(
"Elisa Beckett",
@@ -100,7 +116,9 @@
}
fun createPasskeyInitialUiState(): CreatePasskeyUiState {
- val providerList = CreateFlowUtils.toProviderList(providerList, context)
+ val providerList = CreateFlowUtils.toProviderList(
+ // Handle runtime cast error
+ providerList as List<CreateCredentialProviderData>, context)
// TODO: covert from real requestInfo
val requestDisplayInfo = RequestDisplayInfo(
"Elisa Beckett",
@@ -130,32 +148,29 @@
}
// TODO: below are prototype functionalities. To be removed for productionization.
- private fun testProviderList(): List<ProviderData> {
+ private fun testCreateCredentialProviderList(): List<CreateCredentialProviderData> {
return listOf(
- ProviderData.Builder(
- "com.google",
- "Google Password Manager",
- Icon.createWithResource(context, R.drawable.ic_launcher_foreground))
- .setCredentialEntries(
+ CreateCredentialProviderData.Builder("com.google/com.google.CredentialManagerService")
+ .setSaveEntries(
listOf<Entry>(
newEntry("key1", "subkey-1", "elisa.beckett@gmail.com",
"Elisa Backett", "20 passwords and 7 passkeys saved"),
newEntry("key1", "subkey-2", "elisa.work@google.com",
"Elisa Backett Work", "20 passwords and 7 passkeys saved"),
)
- ).setActionChips(
+ )
+ .setActionChips(
listOf<Entry>(
newEntry("key2", "subkey-1", "Go to Settings", "",
"20 passwords and 7 passkeys saved"),
newEntry("key2", "subkey-2", "Switch Account", "",
"20 passwords and 7 passkeys saved"),
),
- ).build(),
- ProviderData.Builder(
- "com.dashlane",
- "Dashlane",
- Icon.createWithResource(context, R.drawable.ic_launcher_foreground))
- .setCredentialEntries(
+ )
+ .setIsDefaultProvider(true)
+ .build(),
+ CreateCredentialProviderData.Builder("com.dashlane/com.dashlane.CredentialManagerService")
+ .setSaveEntries(
listOf<Entry>(
newEntry("key1", "subkey-3", "elisa.beckett@dashlane.com",
"Elisa Backett", "20 passwords and 7 passkeys saved"),
@@ -172,6 +187,42 @@
)
}
+ private fun testGetCredentialProviderList(): List<GetCredentialProviderData> {
+ return listOf(
+ GetCredentialProviderData.Builder("com.google/com.google.CredentialManagerService")
+ .setCredentialEntries(
+ listOf<Entry>(
+ newEntry("key1", "subkey-1", "elisa.beckett@gmail.com",
+ "Elisa Backett", "20 passwords and 7 passkeys saved"),
+ newEntry("key1", "subkey-2", "elisa.work@google.com",
+ "Elisa Backett Work", "20 passwords and 7 passkeys saved"),
+ )
+ ).setActionChips(
+ listOf<Entry>(
+ newEntry("key2", "subkey-1", "Go to Settings", "",
+ "20 passwords and 7 passkeys saved"),
+ newEntry("key2", "subkey-2", "Switch Account", "",
+ "20 passwords and 7 passkeys saved"),
+ ),
+ ).build(),
+ GetCredentialProviderData.Builder("com.dashlane/com.dashlane.CredentialManagerService")
+ .setCredentialEntries(
+ listOf<Entry>(
+ newEntry("key1", "subkey-3", "elisa.beckett@dashlane.com",
+ "Elisa Backett", "20 passwords and 7 passkeys saved"),
+ newEntry("key1", "subkey-4", "elisa.work@dashlane.com",
+ "Elisa Backett Work", "20 passwords and 7 passkeys saved"),
+ )
+ ).setActionChips(
+ listOf<Entry>(
+ newEntry("key2", "subkey-3", "Manage Accounts",
+ "Manage your accounts in the dashlane app",
+ "20 passwords and 7 passkeys saved"),
+ ),
+ ).build(),
+ )
+ }
+
private fun newEntry(
key: String,
subkey: String,
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt b/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt
index 2ba8748..bf0dba2 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt
@@ -18,7 +18,8 @@
import android.content.Context
import android.credentials.ui.Entry
-import android.credentials.ui.ProviderData
+import android.credentials.ui.GetCredentialProviderData
+import android.credentials.ui.CreateCredentialProviderData
import com.android.credentialmanager.createflow.CreateOptionInfo
import com.android.credentialmanager.getflow.CredentialOptionInfo
import com.android.credentialmanager.getflow.ProviderInfo
@@ -28,7 +29,7 @@
companion object {
fun toProviderList(
- providerDataList: List<ProviderData>,
+ providerDataList: List<GetCredentialProviderData>,
context: Context,
): List<ProviderInfo> {
return providerDataList.map {
@@ -36,9 +37,10 @@
// TODO: replace to extract from the service data structure when available
icon = context.getDrawable(R.drawable.ic_passkey)!!,
name = it.providerFlattenedComponentName,
- displayName = it.providerDisplayName,
+ // TODO: get the service display name and icon from the component name.
+ displayName = it.providerFlattenedComponentName,
credentialTypeIcon = context.getDrawable(R.drawable.ic_passkey)!!,
- credentialOptions = toCredentialOptionInfoList(it.credentialEntries, context)
+ credentialOptions = toCredentialOptionInfoList(it.credentialEntries, context),
)
}
}
@@ -72,7 +74,7 @@
companion object {
fun toProviderList(
- providerDataList: List<ProviderData>,
+ providerDataList: List<CreateCredentialProviderData>,
context: Context,
): List<com.android.credentialmanager.createflow.ProviderInfo> {
return providerDataList.map {
@@ -80,9 +82,11 @@
// TODO: replace to extract from the service data structure when available
icon = context.getDrawable(R.drawable.ic_passkey)!!,
name = it.providerFlattenedComponentName,
- displayName = it.providerDisplayName,
+ // TODO: get the service display name and icon from the component name.
+ displayName = it.providerFlattenedComponentName,
credentialTypeIcon = context.getDrawable(R.drawable.ic_passkey)!!,
- createOptions = toCreationOptionInfoList(it.credentialEntries, context),
+ createOptions = toCreationOptionInfoList(it.saveEntries, context),
+ isDefault = it.isDefaultProvider,
)
}
}
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt
index cb2bf10..db0f337e 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt
@@ -24,6 +24,7 @@
val displayName: String,
val credentialTypeIcon: Drawable,
val createOptions: List<CreateOptionInfo>,
+ val isDefault: Boolean,
)
data class CreateOptionInfo(
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreatePasskeyComponents.kt b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreatePasskeyComponents.kt
index 8e30208..aeea46a 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreatePasskeyComponents.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreatePasskeyComponents.kt
@@ -39,8 +39,8 @@
import androidx.compose.ui.unit.dp
import androidx.core.graphics.drawable.toBitmap
import com.android.credentialmanager.R
-import com.android.credentialmanager.jetpack.CredentialEntryUi.Companion.TYPE_PASSWORD_CREDENTIAL
-import com.android.credentialmanager.jetpack.CredentialEntryUi.Companion.TYPE_PUBLIC_KEY_CREDENTIAL
+import com.android.credentialmanager.jetpack.provider.CredentialEntryUi.Companion.TYPE_PASSWORD_CREDENTIAL
+import com.android.credentialmanager.jetpack.provider.CredentialEntryUi.Companion.TYPE_PUBLIC_KEY_CREDENTIAL
import com.android.credentialmanager.ui.theme.Grey100
import com.android.credentialmanager.ui.theme.Shapes
import com.android.credentialmanager.ui.theme.Typography
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/CreateCredentialRequest.kt b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/CreateCredentialRequest.kt
new file mode 100644
index 0000000..7e7dbde
--- /dev/null
+++ b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/CreateCredentialRequest.kt
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.credentialmanager.jetpack.developer
+
+import android.credentials.Credential
+import android.os.Bundle
+
+/**
+ * Base request class for registering a credential.
+ *
+ * @property type the credential type
+ * @property data the request data in the [Bundle] format
+ * @property requireSystemProvider true if must only be fulfilled by a system provider and false
+ * otherwise
+ */
+open class CreateCredentialRequest(
+ val type: String,
+ val data: Bundle,
+ val requireSystemProvider: Boolean,
+) {
+ companion object {
+ @JvmStatic
+ fun createFrom(from: android.credentials.CreateCredentialRequest): CreateCredentialRequest {
+ return try {
+ when (from.type) {
+ Credential.TYPE_PASSWORD_CREDENTIAL ->
+ CreatePasswordRequest.createFrom(from.data)
+ PublicKeyCredential.TYPE_PUBLIC_KEY_CREDENTIAL ->
+ CreatePublicKeyCredentialBaseRequest.createFrom(from.data)
+ else ->
+ CreateCredentialRequest(from.type, from.data, from.requireSystemProvider())
+ }
+ } catch (e: FrameworkClassParsingException) {
+ CreateCredentialRequest(from.type, from.data, from.requireSystemProvider())
+ }
+ }
+ }
+}
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/CreatePasswordRequest.kt b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/CreatePasswordRequest.kt
new file mode 100644
index 0000000..f0da9f9
--- /dev/null
+++ b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/CreatePasswordRequest.kt
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.credentialmanager.jetpack.developer
+
+import android.credentials.Credential
+import android.os.Bundle
+
+/**
+ * A request to save the user password credential with their password provider.
+ *
+ * @property id the user id associated with the password
+ * @property password the password
+ * @throws NullPointerException If [id] is null
+ * @throws NullPointerException If [password] is null
+ * @throws IllegalArgumentException If [password] is empty
+ */
+class CreatePasswordRequest constructor(
+ val id: String,
+ val password: String,
+) : CreateCredentialRequest(
+ Credential.TYPE_PASSWORD_CREDENTIAL,
+ toBundle(id, password),
+ false,
+) {
+
+ init {
+ require(password.isNotEmpty()) { "password should not be empty" }
+ }
+
+ companion object {
+ const val BUNDLE_KEY_ID = "androidx.credentials.BUNDLE_KEY_ID"
+ const val BUNDLE_KEY_PASSWORD = "androidx.credentials.BUNDLE_KEY_PASSWORD"
+
+ @JvmStatic
+ internal fun toBundle(id: String, password: String): Bundle {
+ val bundle = Bundle()
+ bundle.putString(BUNDLE_KEY_ID, id)
+ bundle.putString(BUNDLE_KEY_PASSWORD, password)
+ return bundle
+ }
+
+ @JvmStatic
+ fun createFrom(data: Bundle): CreatePasswordRequest {
+ try {
+ val id = data.getString(BUNDLE_KEY_ID)
+ val password = data.getString(BUNDLE_KEY_PASSWORD)
+ return CreatePasswordRequest(id!!, password!!)
+ } catch (e: Exception) {
+ throw FrameworkClassParsingException()
+ }
+ }
+ }
+}
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/CreatePublicKeyCredentialBaseRequest.kt b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/CreatePublicKeyCredentialBaseRequest.kt
new file mode 100644
index 0000000..26d61f9
--- /dev/null
+++ b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/CreatePublicKeyCredentialBaseRequest.kt
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.credentialmanager.jetpack.developer
+
+import android.os.Bundle
+
+/**
+ * Base request class for registering a public key credential.
+ *
+ * @property requestJson The request in JSON format
+ * @throws NullPointerException If [requestJson] is null. This is handled by the Kotlin runtime
+ * @throws IllegalArgumentException If [requestJson] is empty
+ *
+ * @hide
+ */
+abstract class CreatePublicKeyCredentialBaseRequest constructor(
+ val requestJson: String,
+ type: String,
+ data: Bundle,
+ requireSystemProvider: Boolean,
+) : CreateCredentialRequest(type, data, requireSystemProvider) {
+
+ init {
+ require(requestJson.isNotEmpty()) { "request json must not be empty" }
+ }
+
+ companion object {
+ const val BUNDLE_KEY_REQUEST_JSON = "androidx.credentials.BUNDLE_KEY_REQUEST_JSON"
+ const val BUNDLE_KEY_SUBTYPE = "androidx.credentials.BUNDLE_KEY_SUBTYPE"
+
+ @JvmStatic
+ fun createFrom(data: Bundle): CreatePublicKeyCredentialBaseRequest {
+ return when (data.getString(BUNDLE_KEY_SUBTYPE)) {
+ CreatePublicKeyCredentialRequest
+ .BUNDLE_VALUE_SUBTYPE_CREATE_PUBLIC_KEY_CREDENTIAL_REQUEST ->
+ CreatePublicKeyCredentialRequestPrivileged.createFrom(data)
+ CreatePublicKeyCredentialRequestPrivileged
+ .BUNDLE_VALUE_SUBTYPE_CREATE_PUBLIC_KEY_CREDENTIAL_REQUEST_PRIVILEGED ->
+ CreatePublicKeyCredentialRequestPrivileged.createFrom(data)
+ else -> throw FrameworkClassParsingException()
+ }
+ }
+ }
+}
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/CreatePublicKeyCredentialRequest.kt b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/CreatePublicKeyCredentialRequest.kt
new file mode 100644
index 0000000..2eda90b
--- /dev/null
+++ b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/CreatePublicKeyCredentialRequest.kt
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.credentialmanager.jetpack.developer
+
+import android.os.Bundle
+
+/**
+ * A request to register a passkey from the user's public key credential provider.
+ *
+ * @property requestJson the request in JSON format
+ * @property allowHybrid defines whether hybrid credentials are allowed to fulfill this request,
+ * true by default
+ * @throws NullPointerException If [requestJson] or [allowHybrid] is null. This is handled by the
+ * Kotlin runtime
+ * @throws IllegalArgumentException If [requestJson] is empty
+ *
+ * @hide
+ */
+class CreatePublicKeyCredentialRequest @JvmOverloads constructor(
+ requestJson: String,
+ @get:JvmName("allowHybrid")
+ val allowHybrid: Boolean = true
+) : CreatePublicKeyCredentialBaseRequest(
+ requestJson,
+ PublicKeyCredential.TYPE_PUBLIC_KEY_CREDENTIAL,
+ toBundle(requestJson, allowHybrid),
+ false,
+) {
+ companion object {
+ const val BUNDLE_KEY_ALLOW_HYBRID = "androidx.credentials.BUNDLE_KEY_ALLOW_HYBRID"
+ const val BUNDLE_VALUE_SUBTYPE_CREATE_PUBLIC_KEY_CREDENTIAL_REQUEST =
+ "androidx.credentials.BUNDLE_VALUE_SUBTYPE_CREATE_PUBLIC_KEY_CREDENTIAL_REQUEST"
+
+ @JvmStatic
+ internal fun toBundle(requestJson: String, allowHybrid: Boolean): Bundle {
+ val bundle = Bundle()
+ bundle.putString(BUNDLE_KEY_SUBTYPE,
+ BUNDLE_VALUE_SUBTYPE_CREATE_PUBLIC_KEY_CREDENTIAL_REQUEST)
+ bundle.putString(BUNDLE_KEY_REQUEST_JSON, requestJson)
+ bundle.putBoolean(BUNDLE_KEY_ALLOW_HYBRID, allowHybrid)
+ return bundle
+ }
+
+ @JvmStatic
+ fun createFrom(data: Bundle): CreatePublicKeyCredentialRequest {
+ try {
+ val requestJson = data.getString(BUNDLE_KEY_REQUEST_JSON)
+ val allowHybrid = data.get(BUNDLE_KEY_ALLOW_HYBRID)
+ return CreatePublicKeyCredentialRequest(requestJson!!, (allowHybrid!!) as Boolean)
+ } catch (e: Exception) {
+ throw FrameworkClassParsingException()
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/CreatePublicKeyCredentialRequestPrivileged.kt b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/CreatePublicKeyCredentialRequestPrivileged.kt
new file mode 100644
index 0000000..36324f8
--- /dev/null
+++ b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/CreatePublicKeyCredentialRequestPrivileged.kt
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.credentialmanager.jetpack.developer
+
+import android.os.Bundle
+
+/**
+ * A privileged request to register a passkey from the user’s public key credential provider, where
+ * the caller can modify the rp. Only callers with privileged permission, e.g. user’s default
+ * brower, caBLE, can use this.
+ *
+ * @property requestJson the privileged request in JSON format
+ * @property allowHybrid defines whether hybrid credentials are allowed to fulfill this request,
+ * true by default
+ * @property rp the expected true RP ID which will override the one in the [requestJson]
+ * @property clientDataHash a hash that is used to verify the [rp] Identity
+ * @throws NullPointerException If any of [allowHybrid], [requestJson], [rp], or [clientDataHash] is
+ * null. This is handled by the Kotlin runtime
+ * @throws IllegalArgumentException If any of [requestJson], [rp], or [clientDataHash] is empty
+ *
+ * @hide
+ */
+class CreatePublicKeyCredentialRequestPrivileged @JvmOverloads constructor(
+ requestJson: String,
+ val rp: String,
+ val clientDataHash: String,
+ @get:JvmName("allowHybrid")
+ val allowHybrid: Boolean = true
+) : CreatePublicKeyCredentialBaseRequest(
+ requestJson,
+ PublicKeyCredential.TYPE_PUBLIC_KEY_CREDENTIAL,
+ toBundle(requestJson, rp, clientDataHash, allowHybrid),
+ false,
+) {
+
+ init {
+ require(rp.isNotEmpty()) { "rp must not be empty" }
+ require(clientDataHash.isNotEmpty()) { "clientDataHash must not be empty" }
+ }
+
+ /** A builder for [CreatePublicKeyCredentialRequestPrivileged]. */
+ class Builder(var requestJson: String, var rp: String, var clientDataHash: String) {
+
+ private var allowHybrid: Boolean = true
+
+ /**
+ * Sets the privileged request in JSON format.
+ */
+ fun setRequestJson(requestJson: String): Builder {
+ this.requestJson = requestJson
+ return this
+ }
+
+ /**
+ * Sets whether hybrid credentials are allowed to fulfill this request, true by default.
+ */
+ fun setAllowHybrid(allowHybrid: Boolean): Builder {
+ this.allowHybrid = allowHybrid
+ return this
+ }
+
+ /**
+ * Sets the expected true RP ID which will override the one in the [requestJson].
+ */
+ fun setRp(rp: String): Builder {
+ this.rp = rp
+ return this
+ }
+
+ /**
+ * Sets a hash that is used to verify the [rp] Identity.
+ */
+ fun setClientDataHash(clientDataHash: String): Builder {
+ this.clientDataHash = clientDataHash
+ return this
+ }
+
+ /** Builds a [CreatePublicKeyCredentialRequestPrivileged]. */
+ fun build(): CreatePublicKeyCredentialRequestPrivileged {
+ return CreatePublicKeyCredentialRequestPrivileged(this.requestJson,
+ this.rp, this.clientDataHash, this.allowHybrid)
+ }
+ }
+
+ companion object {
+ const val BUNDLE_KEY_RP = "androidx.credentials.BUNDLE_KEY_RP"
+ const val BUNDLE_KEY_CLIENT_DATA_HASH =
+ "androidx.credentials.BUNDLE_KEY_CLIENT_DATA_HASH"
+ const val BUNDLE_KEY_ALLOW_HYBRID = "androidx.credentials.BUNDLE_KEY_ALLOW_HYBRID"
+ const val BUNDLE_VALUE_SUBTYPE_CREATE_PUBLIC_KEY_CREDENTIAL_REQUEST_PRIVILEGED =
+ "androidx.credentials.BUNDLE_VALUE_SUBTYPE_CREATE_PUBLIC_KEY_CREDENTIAL_REQUEST_" +
+ "PRIVILEGED"
+
+ @JvmStatic
+ internal fun toBundle(
+ requestJson: String,
+ rp: String,
+ clientDataHash: String,
+ allowHybrid: Boolean
+ ): Bundle {
+ val bundle = Bundle()
+ bundle.putString(BUNDLE_KEY_SUBTYPE,
+ BUNDLE_VALUE_SUBTYPE_CREATE_PUBLIC_KEY_CREDENTIAL_REQUEST_PRIVILEGED)
+ bundle.putString(BUNDLE_KEY_REQUEST_JSON, requestJson)
+ bundle.putString(BUNDLE_KEY_RP, rp)
+ bundle.putString(BUNDLE_KEY_CLIENT_DATA_HASH, clientDataHash)
+ bundle.putBoolean(BUNDLE_KEY_ALLOW_HYBRID, allowHybrid)
+ return bundle
+ }
+
+ @JvmStatic
+ fun createFrom(data: Bundle): CreatePublicKeyCredentialRequestPrivileged {
+ try {
+ val requestJson = data.getString(BUNDLE_KEY_REQUEST_JSON)
+ val rp = data.getString(BUNDLE_KEY_RP)
+ val clientDataHash = data.getString(BUNDLE_KEY_CLIENT_DATA_HASH)
+ val allowHybrid = data.get(BUNDLE_KEY_ALLOW_HYBRID)
+ return CreatePublicKeyCredentialRequestPrivileged(
+ requestJson!!,
+ rp!!,
+ clientDataHash!!,
+ (allowHybrid!!) as Boolean,
+ )
+ } catch (e: Exception) {
+ throw FrameworkClassParsingException()
+ }
+ }
+ }
+}
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/Credential.kt b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/Credential.kt
new file mode 100644
index 0000000..ee08e9e
--- /dev/null
+++ b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/Credential.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.credentialmanager.jetpack.developer
+
+import android.os.Bundle
+
+/**
+ * Base class for a credential with which the user consented to authenticate to the app.
+ *
+ * @property type the credential type
+ * @property data the credential data in the [Bundle] format.
+ */
+open class Credential(val type: String, val data: Bundle)
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/FrameworkClassParsingException.kt b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/FrameworkClassParsingException.kt
new file mode 100644
index 0000000..497c272
--- /dev/null
+++ b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/FrameworkClassParsingException.kt
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.credentialmanager.jetpack.developer
+
+/**
+ * Internal exception used to indicate a parsing error while converting from a framework type to
+ * a jetpack type.
+ *
+ * @hide
+ */
+internal class FrameworkClassParsingException : Exception()
\ No newline at end of file
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/GetCredentialOption.kt b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/GetCredentialOption.kt
new file mode 100644
index 0000000..eb65241
--- /dev/null
+++ b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/GetCredentialOption.kt
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.credentialmanager.jetpack.developer
+
+import android.credentials.Credential
+import android.os.Bundle
+
+/**
+ * Base request class for getting a registered credential.
+ *
+ * @property type the credential type
+ * @property data the request data in the [Bundle] format
+ * @property requireSystemProvider true if must only be fulfilled by a system provider and false
+ * otherwise
+ */
+open class GetCredentialOption(
+ val type: String,
+ val data: Bundle,
+ val requireSystemProvider: Boolean,
+) {
+ companion object {
+ @JvmStatic
+ fun createFrom(from: android.credentials.GetCredentialOption): GetCredentialOption {
+ return try {
+ when (from.type) {
+ Credential.TYPE_PASSWORD_CREDENTIAL ->
+ GetPasswordOption.createFrom(from.data)
+ PublicKeyCredential.TYPE_PUBLIC_KEY_CREDENTIAL ->
+ GetPublicKeyCredentialBaseOption.createFrom(from.data)
+ else ->
+ GetCredentialOption(from.type, from.data, from.requireSystemProvider())
+ }
+ } catch (e: FrameworkClassParsingException) {
+ GetCredentialOption(from.type, from.data, from.requireSystemProvider())
+ }
+ }
+ }
+}
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/GetCredentialRequest.kt b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/GetCredentialRequest.kt
new file mode 100644
index 0000000..7f9256e
--- /dev/null
+++ b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/GetCredentialRequest.kt
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.credentialmanager.jetpack.developer
+
+/**
+ * Encapsulates a request to get a user credential.
+ *
+ * @property getCredentialOptions the list of [GetCredentialOption] from which the user can choose
+ * one to authenticate to the app
+ * @throws IllegalArgumentException If [getCredentialOptions] is empty
+ */
+class GetCredentialRequest constructor(
+ val getCredentialOptions: List<GetCredentialOption>,
+) {
+
+ init {
+ require(getCredentialOptions.isNotEmpty()) { "credentialRequests should not be empty" }
+ }
+
+ /** A builder for [GetCredentialRequest]. */
+ class Builder {
+ private var getCredentialOptions: MutableList<GetCredentialOption> = mutableListOf()
+
+ /** Adds a specific type of [GetCredentialOption]. */
+ fun addGetCredentialOption(getCredentialOption: GetCredentialOption): Builder {
+ getCredentialOptions.add(getCredentialOption)
+ return this
+ }
+
+ /** Sets the list of [GetCredentialOption]. */
+ fun setGetCredentialOptions(getCredentialOptions: List<GetCredentialOption>): Builder {
+ this.getCredentialOptions = getCredentialOptions.toMutableList()
+ return this
+ }
+
+ /**
+ * Builds a [GetCredentialRequest].
+ *
+ * @throws IllegalArgumentException If [getCredentialOptions] is empty
+ */
+ fun build(): GetCredentialRequest {
+ return GetCredentialRequest(getCredentialOptions.toList())
+ }
+ }
+
+ companion object {
+ @JvmStatic
+ fun createFrom(from: android.credentials.GetCredentialRequest): GetCredentialRequest {
+ return GetCredentialRequest(
+ from.getCredentialOptions.map {GetCredentialOption.createFrom(it)}
+ )
+ }
+ }
+}
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/GetPasswordOption.kt b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/GetPasswordOption.kt
new file mode 100644
index 0000000..2facad1
--- /dev/null
+++ b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/GetPasswordOption.kt
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.credentialmanager.jetpack.developer
+
+import android.credentials.Credential
+import android.os.Bundle
+
+/** A request to retrieve the user's saved application password from their password provider. */
+class GetPasswordOption : GetCredentialOption(
+ Credential.TYPE_PASSWORD_CREDENTIAL,
+ Bundle(),
+ false,
+) {
+ companion object {
+ @JvmStatic
+ fun createFrom(data: Bundle): GetPasswordOption {
+ return GetPasswordOption()
+ }
+ }
+}
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/GetPublicKeyCredentialBaseOption.kt b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/GetPublicKeyCredentialBaseOption.kt
new file mode 100644
index 0000000..9b51b30
--- /dev/null
+++ b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/GetPublicKeyCredentialBaseOption.kt
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.credentialmanager.jetpack.developer
+
+import android.os.Bundle
+
+/**
+ * Base request class for getting a registered public key credential.
+ *
+ * @property requestJson the request in JSON format
+ * @throws NullPointerException If [requestJson] is null - auto handled by the
+ * Kotlin runtime
+ * @throws IllegalArgumentException If [requestJson] is empty
+ *
+ * @hide
+ */
+abstract class GetPublicKeyCredentialBaseOption constructor(
+ val requestJson: String,
+ type: String,
+ data: Bundle,
+ requireSystemProvider: Boolean,
+) : GetCredentialOption(type, data, requireSystemProvider) {
+
+ init {
+ require(requestJson.isNotEmpty()) { "request json must not be empty" }
+ }
+
+ companion object {
+ const val BUNDLE_KEY_REQUEST_JSON = "androidx.credentials.BUNDLE_KEY_REQUEST_JSON"
+ const val BUNDLE_KEY_SUBTYPE = "androidx.credentials.BUNDLE_KEY_SUBTYPE"
+
+ @JvmStatic
+ fun createFrom(data: Bundle): GetPublicKeyCredentialBaseOption {
+ return when (data.getString(BUNDLE_KEY_SUBTYPE)) {
+ GetPublicKeyCredentialOption
+ .BUNDLE_VALUE_SUBTYPE_GET_PUBLIC_KEY_CREDENTIAL_OPTION ->
+ GetPublicKeyCredentialOption.createFrom(data)
+ GetPublicKeyCredentialOptionPrivileged
+ .BUNDLE_VALUE_SUBTYPE_GET_PUBLIC_KEY_CREDENTIAL_OPTION_PRIVILEGED ->
+ GetPublicKeyCredentialOptionPrivileged.createFrom(data)
+ else -> throw FrameworkClassParsingException()
+ }
+ }
+ }
+}
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/GetPublicKeyCredentialOption.kt b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/GetPublicKeyCredentialOption.kt
new file mode 100644
index 0000000..6f13c17
--- /dev/null
+++ b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/GetPublicKeyCredentialOption.kt
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.credentialmanager.jetpack.developer
+
+import android.os.Bundle
+
+/**
+ * A request to get passkeys from the user's public key credential provider.
+ *
+ * @property requestJson the request in JSON format
+ * @property allowHybrid defines whether hybrid credentials are allowed to fulfill this request,
+ * true by default
+ * @throws NullPointerException If [requestJson] or [allowHybrid] is null. It is handled by the
+ * Kotlin runtime
+ * @throws IllegalArgumentException If [requestJson] is empty
+ *
+ * @hide
+ */
+class GetPublicKeyCredentialOption @JvmOverloads constructor(
+ requestJson: String,
+ @get:JvmName("allowHybrid")
+ val allowHybrid: Boolean = true,
+) : GetPublicKeyCredentialBaseOption(
+ requestJson,
+ PublicKeyCredential.TYPE_PUBLIC_KEY_CREDENTIAL,
+ toBundle(requestJson, allowHybrid),
+ false
+) {
+ companion object {
+ const val BUNDLE_KEY_ALLOW_HYBRID = "androidx.credentials.BUNDLE_KEY_ALLOW_HYBRID"
+ const val BUNDLE_VALUE_SUBTYPE_GET_PUBLIC_KEY_CREDENTIAL_OPTION =
+ "androidx.credentials.BUNDLE_VALUE_SUBTYPE_GET_PUBLIC_KEY_CREDENTIAL_OPTION"
+
+ @JvmStatic
+ internal fun toBundle(requestJson: String, allowHybrid: Boolean): Bundle {
+ val bundle = Bundle()
+ bundle.putString(BUNDLE_KEY_REQUEST_JSON, requestJson)
+ bundle.putBoolean(BUNDLE_KEY_ALLOW_HYBRID, allowHybrid)
+ return bundle
+ }
+
+ @JvmStatic
+ fun createFrom(data: Bundle): GetPublicKeyCredentialOption {
+ try {
+ val requestJson = data.getString(BUNDLE_KEY_REQUEST_JSON)
+ val allowHybrid = data.get(BUNDLE_KEY_ALLOW_HYBRID)
+ return GetPublicKeyCredentialOption(requestJson!!, (allowHybrid!!) as Boolean)
+ } catch (e: Exception) {
+ throw FrameworkClassParsingException()
+ }
+ }
+ }
+}
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/GetPublicKeyCredentialOptionPrivileged.kt b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/GetPublicKeyCredentialOptionPrivileged.kt
new file mode 100644
index 0000000..79c62a1
--- /dev/null
+++ b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/GetPublicKeyCredentialOptionPrivileged.kt
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.credentialmanager.jetpack.developer
+
+import android.os.Bundle
+
+/**
+ * A privileged request to get passkeys from the user's public key credential provider. The caller
+ * can modify the RP. Only callers with privileged permission (e.g. user's public browser or caBLE)
+ * can use this.
+ *
+ * @property requestJson the privileged request in JSON format
+ * @property allowHybrid defines whether hybrid credentials are allowed to fulfill this request,
+ * true by default
+ * @property rp the expected true RP ID which will override the one in the [requestJson]
+ * @property clientDataHash a hash that is used to verify the [rp] Identity
+ * @throws NullPointerException If any of [allowHybrid], [requestJson], [rp], or [clientDataHash]
+ * is null. This is handled by the Kotlin runtime
+ * @throws IllegalArgumentException If any of [requestJson], [rp], or [clientDataHash] is empty
+ *
+ * @hide
+ */
+class GetPublicKeyCredentialOptionPrivileged @JvmOverloads constructor(
+ requestJson: String,
+ val rp: String,
+ val clientDataHash: String,
+ @get:JvmName("allowHybrid")
+ val allowHybrid: Boolean = true
+) : GetPublicKeyCredentialBaseOption(
+ requestJson,
+ PublicKeyCredential.TYPE_PUBLIC_KEY_CREDENTIAL,
+ toBundle(requestJson, rp, clientDataHash, allowHybrid),
+ false,
+) {
+
+ init {
+ require(rp.isNotEmpty()) { "rp must not be empty" }
+ require(clientDataHash.isNotEmpty()) { "clientDataHash must not be empty" }
+ }
+
+ /** A builder for [GetPublicKeyCredentialOptionPrivileged]. */
+ class Builder(var requestJson: String, var rp: String, var clientDataHash: String) {
+
+ private var allowHybrid: Boolean = true
+
+ /**
+ * Sets the privileged request in JSON format.
+ */
+ fun setRequestJson(requestJson: String): Builder {
+ this.requestJson = requestJson
+ return this
+ }
+
+ /**
+ * Sets whether hybrid credentials are allowed to fulfill this request, true by default.
+ */
+ fun setAllowHybrid(allowHybrid: Boolean): Builder {
+ this.allowHybrid = allowHybrid
+ return this
+ }
+
+ /**
+ * Sets the expected true RP ID which will override the one in the [requestJson].
+ */
+ fun setRp(rp: String): Builder {
+ this.rp = rp
+ return this
+ }
+
+ /**
+ * Sets a hash that is used to verify the [rp] Identity.
+ */
+ fun setClientDataHash(clientDataHash: String): Builder {
+ this.clientDataHash = clientDataHash
+ return this
+ }
+
+ /** Builds a [GetPublicKeyCredentialOptionPrivileged]. */
+ fun build(): GetPublicKeyCredentialOptionPrivileged {
+ return GetPublicKeyCredentialOptionPrivileged(this.requestJson,
+ this.rp, this.clientDataHash, this.allowHybrid)
+ }
+ }
+
+ companion object {
+ const val BUNDLE_KEY_RP = "androidx.credentials.BUNDLE_KEY_RP"
+ const val BUNDLE_KEY_CLIENT_DATA_HASH =
+ "androidx.credentials.BUNDLE_KEY_CLIENT_DATA_HASH"
+ const val BUNDLE_KEY_ALLOW_HYBRID = "androidx.credentials.BUNDLE_KEY_ALLOW_HYBRID"
+ const val BUNDLE_VALUE_SUBTYPE_GET_PUBLIC_KEY_CREDENTIAL_OPTION_PRIVILEGED =
+ "androidx.credentials.BUNDLE_VALUE_SUBTYPE_GET_PUBLIC_KEY_CREDENTIAL_OPTION" +
+ "_PRIVILEGED"
+
+ @JvmStatic
+ internal fun toBundle(
+ requestJson: String,
+ rp: String,
+ clientDataHash: String,
+ allowHybrid: Boolean
+ ): Bundle {
+ val bundle = Bundle()
+ bundle.putString(BUNDLE_KEY_REQUEST_JSON, requestJson)
+ bundle.putString(BUNDLE_KEY_RP, rp)
+ bundle.putString(BUNDLE_KEY_CLIENT_DATA_HASH, clientDataHash)
+ bundle.putBoolean(BUNDLE_KEY_ALLOW_HYBRID, allowHybrid)
+ return bundle
+ }
+
+ @JvmStatic
+ fun createFrom(data: Bundle): GetPublicKeyCredentialOptionPrivileged {
+ try {
+ val requestJson = data.getString(BUNDLE_KEY_REQUEST_JSON)
+ val rp = data.getString(BUNDLE_KEY_RP)
+ val clientDataHash = data.getString(BUNDLE_KEY_CLIENT_DATA_HASH)
+ val allowHybrid = data.get(BUNDLE_KEY_ALLOW_HYBRID)
+ return GetPublicKeyCredentialOptionPrivileged(
+ requestJson!!,
+ rp!!,
+ clientDataHash!!,
+ (allowHybrid!!) as Boolean,
+ )
+ } catch (e: Exception) {
+ throw FrameworkClassParsingException()
+ }
+ }
+ }
+}
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/PublicKeyCredential.kt b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/PublicKeyCredential.kt
new file mode 100644
index 0000000..b45a63b
--- /dev/null
+++ b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/PublicKeyCredential.kt
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.credentialmanager.jetpack.developer
+
+import android.os.Bundle
+
+/**
+ * Represents the user's passkey credential granted by the user for app sign-in.
+ *
+ * @property authenticationResponseJson the public key credential authentication response in
+ * JSON format that follows the standard webauthn json format shown at
+ * [this w3c link](https://w3c.github.io/webauthn/#dictdef-authenticationresponsejson)
+ * @throws NullPointerException If [authenticationResponseJson] is null. This is handled by the
+ * kotlin runtime
+ * @throws IllegalArgumentException If [authenticationResponseJson] is empty
+ *
+ * @hide
+ */
+class PublicKeyCredential constructor(
+ val authenticationResponseJson: String
+) : Credential(
+ TYPE_PUBLIC_KEY_CREDENTIAL,
+ toBundle(authenticationResponseJson)
+) {
+
+ init {
+ require(authenticationResponseJson.isNotEmpty()) {
+ "authentication response JSON must not be empty" }
+ }
+ companion object {
+ /** The type value for public key credential related operations. */
+ const val TYPE_PUBLIC_KEY_CREDENTIAL: String =
+ "androidx.credentials.TYPE_PUBLIC_KEY_CREDENTIAL"
+ const val BUNDLE_KEY_AUTHENTICATION_RESPONSE_JSON =
+ "androidx.credentials.BUNDLE_KEY_AUTHENTICATION_RESPONSE_JSON"
+
+ @JvmStatic
+ internal fun toBundle(authenticationResponseJson: String): Bundle {
+ val bundle = Bundle()
+ bundle.putString(BUNDLE_KEY_AUTHENTICATION_RESPONSE_JSON, authenticationResponseJson)
+ return bundle
+ }
+ }
+}
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/jetpack/ActionUi.kt b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/provider/ActionUi.kt
similarity index 96%
rename from packages/CredentialManager/src/com/android/credentialmanager/jetpack/ActionUi.kt
rename to packages/CredentialManager/src/com/android/credentialmanager/jetpack/provider/ActionUi.kt
index d4341b4..1e639fe 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/jetpack/ActionUi.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/provider/ActionUi.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.credentialmanager.jetpack
+package com.android.credentialmanager.jetpack.provider
import android.app.slice.Slice
import android.credentials.ui.Entry
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/jetpack/CredentialEntryUi.kt b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/provider/CredentialEntryUi.kt
similarity index 96%
rename from packages/CredentialManager/src/com/android/credentialmanager/jetpack/CredentialEntryUi.kt
rename to packages/CredentialManager/src/com/android/credentialmanager/jetpack/provider/CredentialEntryUi.kt
index d6f1b5f..12ab436 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/jetpack/CredentialEntryUi.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/provider/CredentialEntryUi.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.credentialmanager.jetpack
+package com.android.credentialmanager.jetpack.provider
import android.app.slice.Slice
import android.graphics.drawable.Icon
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/jetpack/PasskeyCredentialEntryUi.kt b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/provider/PasskeyCredentialEntryUi.kt
similarity index 97%
rename from packages/CredentialManager/src/com/android/credentialmanager/jetpack/PasskeyCredentialEntryUi.kt
rename to packages/CredentialManager/src/com/android/credentialmanager/jetpack/provider/PasskeyCredentialEntryUi.kt
index bb3b206..c5dbe66 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/jetpack/PasskeyCredentialEntryUi.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/provider/PasskeyCredentialEntryUi.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.credentialmanager.jetpack
+package com.android.credentialmanager.jetpack.provider
import android.app.slice.Slice
import android.credentials.ui.Entry
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/jetpack/PasswordCredentialEntryUi.kt b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/provider/PasswordCredentialEntryUi.kt
similarity index 97%
rename from packages/CredentialManager/src/com/android/credentialmanager/jetpack/PasswordCredentialEntryUi.kt
rename to packages/CredentialManager/src/com/android/credentialmanager/jetpack/provider/PasswordCredentialEntryUi.kt
index 7311b70..5049503 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/jetpack/PasswordCredentialEntryUi.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/provider/PasswordCredentialEntryUi.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.credentialmanager.jetpack
+package com.android.credentialmanager.jetpack.provider
import android.app.slice.Slice
import android.credentials.ui.Entry
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/jetpack/SaveEntryUi.kt b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/provider/SaveEntryUi.kt
similarity index 97%
rename from packages/CredentialManager/src/com/android/credentialmanager/jetpack/SaveEntryUi.kt
rename to packages/CredentialManager/src/com/android/credentialmanager/jetpack/provider/SaveEntryUi.kt
index fad3309..b260cf6 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/jetpack/SaveEntryUi.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/provider/SaveEntryUi.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.credentialmanager.jetpack
+package com.android.credentialmanager.jetpack.provider
import android.app.slice.Slice
import android.credentials.ui.Entry
diff --git a/packages/SettingsLib/Android.bp b/packages/SettingsLib/Android.bp
index c659525..f170ead 100644
--- a/packages/SettingsLib/Android.bp
+++ b/packages/SettingsLib/Android.bp
@@ -54,6 +54,7 @@
"SettingsLibSettingsTransition",
"SettingsLibButtonPreference",
"SettingsLibDeviceStateRotationLock",
+ "SettingsLibProfileSelector",
"setupdesign",
"zxing-core-1.7",
"androidx.room_room-runtime",
diff --git a/packages/SettingsLib/ProfileSelector/Android.bp b/packages/SettingsLib/ProfileSelector/Android.bp
new file mode 100644
index 0000000..250cd75
--- /dev/null
+++ b/packages/SettingsLib/ProfileSelector/Android.bp
@@ -0,0 +1,27 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+android_library {
+ name: "SettingsLibProfileSelector",
+
+ srcs: ["src/**/*.java"],
+ resource_dirs: ["res"],
+
+ static_libs: [
+ "com.google.android.material_material",
+ "SettingsLibSettingsTheme",
+ ],
+
+ sdk_version: "system_current",
+ min_sdk_version: "23",
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.mediaprovider",
+ ],
+}
diff --git a/packages/SettingsLib/ProfileSelector/AndroidManifest.xml b/packages/SettingsLib/ProfileSelector/AndroidManifest.xml
new file mode 100644
index 0000000..a57469e
--- /dev/null
+++ b/packages/SettingsLib/ProfileSelector/AndroidManifest.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.settingslib.widget">
+
+ <uses-sdk android:minSdkVersion="23" />
+</manifest>
diff --git a/packages/SettingsLib/res/color-night-v31/settingslib_tabs_indicator_color.xml b/packages/SettingsLib/ProfileSelector/res/color-night/settingslib_tabs_indicator_color.xml
similarity index 100%
rename from packages/SettingsLib/res/color-night-v31/settingslib_tabs_indicator_color.xml
rename to packages/SettingsLib/ProfileSelector/res/color-night/settingslib_tabs_indicator_color.xml
diff --git a/packages/SettingsLib/res/color-night-v31/settingslib_tabs_text_color.xml b/packages/SettingsLib/ProfileSelector/res/color-night/settingslib_tabs_text_color.xml
similarity index 100%
rename from packages/SettingsLib/res/color-night-v31/settingslib_tabs_text_color.xml
rename to packages/SettingsLib/ProfileSelector/res/color-night/settingslib_tabs_text_color.xml
diff --git a/packages/SettingsLib/res/color-v31/settingslib_tabs_indicator_color.xml b/packages/SettingsLib/ProfileSelector/res/color/settingslib_tabs_indicator_color.xml
similarity index 100%
rename from packages/SettingsLib/res/color-v31/settingslib_tabs_indicator_color.xml
rename to packages/SettingsLib/ProfileSelector/res/color/settingslib_tabs_indicator_color.xml
diff --git a/packages/SettingsLib/res/color-v31/settingslib_tabs_text_color.xml b/packages/SettingsLib/ProfileSelector/res/color/settingslib_tabs_text_color.xml
similarity index 100%
rename from packages/SettingsLib/res/color-v31/settingslib_tabs_text_color.xml
rename to packages/SettingsLib/ProfileSelector/res/color/settingslib_tabs_text_color.xml
diff --git a/packages/SettingsLib/res/drawable-v31/settingslib_tabs_background.xml b/packages/SettingsLib/ProfileSelector/res/drawable/settingslib_tabs_background.xml
similarity index 100%
rename from packages/SettingsLib/res/drawable-v31/settingslib_tabs_background.xml
rename to packages/SettingsLib/ProfileSelector/res/drawable/settingslib_tabs_background.xml
diff --git a/packages/SettingsLib/res/drawable-v31/settingslib_tabs_indicator_background.xml b/packages/SettingsLib/ProfileSelector/res/drawable/settingslib_tabs_indicator_background.xml
similarity index 100%
rename from packages/SettingsLib/res/drawable-v31/settingslib_tabs_indicator_background.xml
rename to packages/SettingsLib/ProfileSelector/res/drawable/settingslib_tabs_indicator_background.xml
diff --git a/packages/SettingsLib/ProfileSelector/res/layout/tab_fragment.xml b/packages/SettingsLib/ProfileSelector/res/layout/tab_fragment.xml
new file mode 100644
index 0000000..0448c6c
--- /dev/null
+++ b/packages/SettingsLib/ProfileSelector/res/layout/tab_fragment.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:theme="@style/Theme.MaterialComponents.DayNight"
+ android:id="@+id/tab_container"
+ android:clipToPadding="true"
+ android:clipChildren="true"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <com.google.android.material.tabs.TabLayout
+ android:id="@+id/tabs"
+ style="@style/SettingsLibTabsStyle"/>
+
+ <androidx.viewpager2.widget.ViewPager2
+ android:id="@+id/view_pager"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ </androidx.viewpager2.widget.ViewPager2>
+</LinearLayout>
\ No newline at end of file
diff --git a/packages/SettingsLib/ProfileSelector/res/values/strings.xml b/packages/SettingsLib/ProfileSelector/res/values/strings.xml
new file mode 100644
index 0000000..68d4047
--- /dev/null
+++ b/packages/SettingsLib/ProfileSelector/res/values/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+ <!-- Header for items under the personal user [CHAR LIMIT=30] -->
+ <string name="settingslib_category_personal">Personal</string>
+ <!-- Header for items under the work user [CHAR LIMIT=30] -->
+ <string name="settingslib_category_work">Work</string>
+</resources>
\ No newline at end of file
diff --git a/packages/SettingsLib/res/values-v31/styles.xml b/packages/SettingsLib/ProfileSelector/res/values/styles.xml
similarity index 100%
rename from packages/SettingsLib/res/values-v31/styles.xml
rename to packages/SettingsLib/ProfileSelector/res/values/styles.xml
diff --git a/packages/SettingsLib/ProfileSelector/src/com/android/settingslib/widget/ProfileSelectFragment.java b/packages/SettingsLib/ProfileSelector/src/com/android/settingslib/widget/ProfileSelectFragment.java
new file mode 100644
index 0000000..ac426ed
--- /dev/null
+++ b/packages/SettingsLib/ProfileSelector/src/com/android/settingslib/widget/ProfileSelectFragment.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.widget;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.fragment.app.Fragment;
+import androidx.viewpager2.widget.ViewPager2;
+
+import com.google.android.material.tabs.TabLayout;
+import com.google.android.material.tabs.TabLayoutMediator;
+
+/**
+ * Base fragment class for profile settings.
+ */
+public abstract class ProfileSelectFragment extends Fragment {
+
+ /**
+ * Personal or Work profile tab of {@link ProfileSelectFragment}
+ * <p>0: Personal tab.
+ * <p>1: Work profile tab.
+ */
+ public static final String EXTRA_SHOW_FRAGMENT_TAB =
+ ":settings:show_fragment_tab";
+
+ /**
+ * Used in fragment argument with Extra key EXTRA_SHOW_FRAGMENT_TAB
+ */
+ public static final int PERSONAL_TAB = 0;
+
+ /**
+ * Used in fragment argument with Extra key EXTRA_SHOW_FRAGMENT_TAB
+ */
+ public static final int WORK_TAB = 1;
+
+ private ViewGroup mContentView;
+
+ private ViewPager2 mViewPager;
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ // Defines the xml file for the fragment
+ mContentView = (ViewGroup) inflater.inflate(R.layout.tab_fragment, container, false);
+
+ final Activity activity = getActivity();
+ final int titleResId = getTitleResId();
+ if (titleResId > 0) {
+ activity.setTitle(titleResId);
+ }
+ final int selectedTab = getTabId(activity, getArguments());
+
+ final View tabContainer = mContentView.findViewById(R.id.tab_container);
+ mViewPager = tabContainer.findViewById(R.id.view_pager);
+ mViewPager.setAdapter(new ProfileViewPagerAdapter(this));
+ final TabLayout tabs = tabContainer.findViewById(R.id.tabs);
+ new TabLayoutMediator(tabs, mViewPager,
+ (tab, position) -> tab.setText(getPageTitle(position))
+ ).attach();
+
+ tabContainer.setVisibility(View.VISIBLE);
+ final TabLayout.Tab tab = tabs.getTabAt(selectedTab);
+ tab.select();
+
+ return mContentView;
+ }
+
+ /**
+ * create Personal or Work profile fragment
+ * <p>0: Personal profile.
+ * <p>1: Work profile.
+ */
+ public abstract Fragment createFragment(int position);
+
+ /**
+ * Returns a resource ID of the title
+ * Override this if the title needs to be updated dynamically.
+ */
+ public int getTitleResId() {
+ return 0;
+ }
+
+ int getTabId(Activity activity, Bundle bundle) {
+ if (bundle != null) {
+ final int extraTab = bundle.getInt(EXTRA_SHOW_FRAGMENT_TAB, -1);
+ if (extraTab != -1) {
+ return extraTab;
+ }
+ }
+ return PERSONAL_TAB;
+ }
+
+ private CharSequence getPageTitle(int position) {
+ if (position == WORK_TAB) {
+ return getContext().getString(R.string.settingslib_category_work);
+ }
+
+ return getString(R.string.settingslib_category_personal);
+ }
+}
diff --git a/packages/SettingsLib/ProfileSelector/src/com/android/settingslib/widget/ProfileViewPagerAdapter.java b/packages/SettingsLib/ProfileSelector/src/com/android/settingslib/widget/ProfileViewPagerAdapter.java
new file mode 100644
index 0000000..daf2564
--- /dev/null
+++ b/packages/SettingsLib/ProfileSelector/src/com/android/settingslib/widget/ProfileViewPagerAdapter.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.widget;
+
+import androidx.fragment.app.Fragment;
+import androidx.viewpager2.adapter.FragmentStateAdapter;
+
+/**
+ * ViewPager Adapter to handle between TabLayout and ViewPager2
+ */
+public class ProfileViewPagerAdapter extends FragmentStateAdapter {
+
+ private final ProfileSelectFragment mParentFragments;
+
+ ProfileViewPagerAdapter(ProfileSelectFragment fragment) {
+ super(fragment);
+ mParentFragments = fragment;
+ }
+
+ @Override
+ public Fragment createFragment(int position) {
+ return mParentFragments.createFragment(position);
+ }
+
+ @Override
+ public int getItemCount() {
+ return 2;
+ }
+}
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/Android.bp b/packages/SettingsLib/SelectorWithWidgetPreference/Android.bp
index bcc64d3..b5a21bd 100644
--- a/packages/SettingsLib/SelectorWithWidgetPreference/Android.bp
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/Android.bp
@@ -23,5 +23,6 @@
apex_available: [
"//apex_available:platform",
"com.android.permission",
+ "com.android.mediaprovider",
],
}
diff --git a/packages/SettingsLib/SettingsTheme/Android.bp b/packages/SettingsLib/SettingsTheme/Android.bp
index 82e0220..939977f 100644
--- a/packages/SettingsLib/SettingsTheme/Android.bp
+++ b/packages/SettingsLib/SettingsTheme/Android.bp
@@ -24,5 +24,6 @@
"com.android.permission",
"com.android.adservices",
"com.android.healthconnect",
+ "com.android.mediaprovider",
],
}
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/home/HomePage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/home/HomePage.kt
index 83e3f78..04d0fe0 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/home/HomePage.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/home/HomePage.kt
@@ -18,7 +18,6 @@
import android.os.Bundle
import androidx.compose.runtime.Composable
-import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import com.android.settingslib.spa.framework.common.SettingsEntry
import com.android.settingslib.spa.framework.common.SettingsPageProvider
@@ -60,9 +59,13 @@
)
}
+ override fun getTitle(arguments: Bundle?): String {
+ return SpaEnvironmentFactory.instance.appContext.getString(R.string.app_name)
+ }
+
@Composable
override fun Page(arguments: Bundle?) {
- HomeScaffold(title = stringResource(R.string.app_name)) {
+ HomeScaffold(title = getTitle(arguments)) {
for (entry in buildEntry(arguments)) {
if (entry.owner.isCreateBy(SettingsPageProviderEnum.ARGUMENT.name)) {
entry.UiLayout(ArgumentPageModel.buildArgument(intParam = 0))
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/ArgumentPage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/ArgumentPage.kt
index 60ff362..7958d11 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/ArgumentPage.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/ArgumentPage.kt
@@ -99,9 +99,13 @@
}
}
+ override fun getTitle(arguments: Bundle?): String {
+ return ArgumentPageModel.genPageTitle()
+ }
+
@Composable
override fun Page(arguments: Bundle?) {
- RegularScaffold(title = ArgumentPageModel.create(arguments).genPageTitle()) {
+ RegularScaffold(title = getTitle(arguments)) {
for (entry in buildEntry(arguments)) {
if (entry.toPage != null) {
entry.UiLayout(ArgumentPageModel.buildNextArgument(arguments))
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/ArgumentPageModel.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/ArgumentPageModel.kt
index e5e3c67..5f15865 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/ArgumentPageModel.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/ArgumentPageModel.kt
@@ -81,6 +81,10 @@
return EntrySearchData(title = PAGE_TITLE, keyword = ARGUMENT_PAGE_KEYWORDS)
}
+ fun genPageTitle(): String {
+ return PAGE_TITLE
+ }
+
@Composable
fun create(arguments: Bundle?): ArgumentPageModel {
val pageModel: ArgumentPageModel = viewModel(key = arguments.toString())
@@ -89,7 +93,6 @@
}
}
- private val title = PAGE_TITLE
private var arguments: Bundle? = null
private var stringParam: String? = null
private var intParam: Int? = null
@@ -104,11 +107,6 @@
}
@Composable
- fun genPageTitle(): String {
- return title
- }
-
- @Composable
fun genStringParamPreferenceModel(): PreferenceModel {
return object : PreferenceModel {
override val title = STRING_PARAM_TITLE
@@ -131,7 +129,7 @@
"$INT_PARAM_NAME=" + intParam!!
)
return object : PreferenceModel {
- override val title = genPageTitle()
+ override val title = PAGE_TITLE
override val summary = stateOf(summaryArray.joinToString(", "))
override val onClick = navigator(
SettingsPageProviderEnum.ARGUMENT.displayName + parameter.navLink(arguments)
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/FooterPage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/FooterPage.kt
index 0fc2a5f..c903cfd 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/FooterPage.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/FooterPage.kt
@@ -67,9 +67,13 @@
}
}
+ override fun getTitle(arguments: Bundle?): String {
+ return TITLE
+ }
+
@Composable
override fun Page(arguments: Bundle?) {
- RegularScaffold(title = TITLE) {
+ RegularScaffold(title = getTitle(arguments)) {
for (entry in buildEntry(arguments)) {
entry.UiLayout()
}
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/IllustrationPage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/IllustrationPage.kt
index a64d4a5..e10cf3a 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/IllustrationPage.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/IllustrationPage.kt
@@ -31,7 +31,6 @@
import com.android.settingslib.spa.widget.ResourceType
import com.android.settingslib.spa.widget.preference.Preference
import com.android.settingslib.spa.widget.preference.PreferenceModel
-import com.android.settingslib.spa.widget.scaffold.RegularScaffold
private const val TITLE = "Sample Illustration"
@@ -82,13 +81,8 @@
}
}
- @Composable
- override fun Page(arguments: Bundle?) {
- RegularScaffold(title = TITLE) {
- for (entry in buildEntry(arguments)) {
- entry.UiLayout()
- }
- }
+ override fun getTitle(arguments: Bundle?): String {
+ return TITLE
}
}
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/ProgressBarPage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/ProgressBarPage.kt
index dc45df4..9136b04 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/ProgressBarPage.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/ProgressBarPage.kt
@@ -60,6 +60,10 @@
}
}
+ override fun getTitle(arguments: Bundle?): String {
+ return TITLE
+ }
+
@Composable
override fun Page(arguments: Bundle?) {
// Mocks a loading time of 2 seconds.
@@ -69,7 +73,7 @@
loading = false
}
- RegularScaffold(title = TITLE) {
+ RegularScaffold(title = getTitle(arguments)) {
// Auto update the progress and finally jump tp 0.4f.
var progress by remember { mutableStateOf(0f) }
LaunchedEffect(Unit) {
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/SettingsPagerPage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/SettingsPagerPage.kt
index b38178b..cb58a95 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/SettingsPagerPage.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/SettingsPagerPage.kt
@@ -49,9 +49,13 @@
}
}
+ override fun getTitle(arguments: Bundle?): String {
+ return TITLE
+ }
+
@Composable
override fun Page(arguments: Bundle?) {
- SettingsScaffold(title = TITLE) { paddingValues ->
+ SettingsScaffold(title = getTitle(arguments)) { paddingValues ->
Box(Modifier.padding(paddingValues)) {
SettingsPager(listOf("Personal", "Work")) {
PlaceholderTitle("Page $it")
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/SliderPage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/SliderPage.kt
index 7567c6d..73b34a5 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/SliderPage.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/SliderPage.kt
@@ -37,7 +37,6 @@
import com.android.settingslib.spa.widget.preference.SliderPreferenceModel
import com.android.settingslib.spa.widget.preference.Preference
import com.android.settingslib.spa.widget.preference.PreferenceModel
-import com.android.settingslib.spa.widget.scaffold.RegularScaffold
private const val TITLE = "Sample Slider"
@@ -119,13 +118,8 @@
}
}
- @Composable
- override fun Page(arguments: Bundle?) {
- RegularScaffold(title = TITLE) {
- for (entry in buildEntry(arguments)) {
- entry.UiLayout()
- }
- }
+ override fun getTitle(arguments: Bundle?): String {
+ return TITLE
}
}
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/MainSwitchPreferencePage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/MainSwitchPreferencePage.kt
index a8e4938..f38a8d4 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/MainSwitchPreferencePage.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/MainSwitchPreferencePage.kt
@@ -33,7 +33,6 @@
import com.android.settingslib.spa.widget.preference.Preference
import com.android.settingslib.spa.widget.preference.PreferenceModel
import com.android.settingslib.spa.widget.preference.SwitchPreferenceModel
-import com.android.settingslib.spa.widget.scaffold.RegularScaffold
private const val TITLE = "Sample MainSwitchPreference"
@@ -72,13 +71,8 @@
}
}
- @Composable
- override fun Page(arguments: Bundle?) {
- RegularScaffold(title = TITLE) {
- for (entry in buildEntry(arguments)) {
- entry.UiLayout()
- }
- }
+ override fun getTitle(arguments: Bundle?): String {
+ return TITLE
}
}
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/PreferenceMain.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/PreferenceMain.kt
index 165eaa0..61925a7 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/PreferenceMain.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/PreferenceMain.kt
@@ -17,7 +17,6 @@
package com.android.settingslib.spa.gallery.preference
import android.os.Bundle
-import androidx.compose.runtime.Composable
import com.android.settingslib.spa.framework.common.SettingsEntry
import com.android.settingslib.spa.framework.common.SettingsEntryBuilder
import com.android.settingslib.spa.framework.common.SettingsPageProvider
@@ -25,7 +24,6 @@
import com.android.settingslib.spa.framework.compose.navigator
import com.android.settingslib.spa.widget.preference.Preference
import com.android.settingslib.spa.widget.preference.PreferenceModel
-import com.android.settingslib.spa.widget.scaffold.RegularScaffold
private const val TITLE = "Category: Preference"
@@ -54,12 +52,7 @@
}
}
- @Composable
- override fun Page(arguments: Bundle?) {
- RegularScaffold(title = TITLE) {
- for (entry in buildEntry(arguments)) {
- entry.UiLayout()
- }
- }
+ override fun getTitle(arguments: Bundle?): String {
+ return TITLE
}
}
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/PreferencePage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/PreferencePage.kt
index 2c2782b..26e59ff 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/PreferencePage.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/PreferencePage.kt
@@ -49,7 +49,6 @@
import com.android.settingslib.spa.widget.preference.Preference
import com.android.settingslib.spa.widget.preference.PreferenceModel
import com.android.settingslib.spa.widget.preference.SimplePreferenceMacro
-import com.android.settingslib.spa.widget.scaffold.RegularScaffold
import com.android.settingslib.spa.widget.ui.SettingsIcon
private const val TAG = "PreferencePage"
@@ -128,11 +127,11 @@
.setStatusDataFn { EntryStatusData(isDisabled = false) }
.setUiLayoutFn {
val model = PreferencePageModel.create()
- val asyncSummary = remember { model.getAsyncSummary() }
Preference(
object : PreferenceModel {
override val title = ASYNC_PREFERENCE_TITLE
- override val summary = asyncSummary
+ override val summary = model.asyncSummary
+ override val enabled = model.asyncEnable
}
)
}.build()
@@ -204,13 +203,8 @@
}
}
- @Composable
- override fun Page(arguments: Bundle?) {
- RegularScaffold(title = PAGE_TITLE) {
- for (entry in buildEntry(arguments)) {
- entry.UiLayout()
- }
- }
+ override fun getTitle(arguments: Bundle?): String {
+ return PAGE_TITLE
}
}
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/PreferencePageModel.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/PreferencePageModel.kt
index 1e64b2e..d874417 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/PreferencePageModel.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/PreferencePageModel.kt
@@ -59,7 +59,8 @@
private val spaLogger = SpaEnvironmentFactory.instance.logger
- private val asyncSummary = mutableStateOf(" ")
+ val asyncSummary = mutableStateOf("(loading)")
+ val asyncEnable = mutableStateOf(false)
private val manualUpdater = mutableStateOf(0)
@@ -87,16 +88,13 @@
override fun initialize(arguments: Bundle?) {
spaLogger.message(TAG, "initialize with args " + arguments.toString())
viewModelScope.launch(Dispatchers.IO) {
+ // Loading your data here.
delay(2000L)
asyncSummary.value = ASYNC_PREFERENCE_SUMMARY
+ asyncEnable.value = true
}
}
- fun getAsyncSummary(): State<String> {
- spaLogger.message(TAG, "getAsyncSummary")
- return asyncSummary
- }
-
fun getManualUpdaterSummary(): State<String> {
spaLogger.message(TAG, "getManualUpdaterSummary")
return derivedStateOf { manualUpdater.value.toString() }
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/SwitchPreferencePage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/SwitchPreferencePage.kt
index 46b44ca..367766a 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/SwitchPreferencePage.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/SwitchPreferencePage.kt
@@ -34,7 +34,6 @@
import com.android.settingslib.spa.widget.preference.PreferenceModel
import com.android.settingslib.spa.widget.preference.SwitchPreference
import com.android.settingslib.spa.widget.preference.SwitchPreferenceModel
-import com.android.settingslib.spa.widget.scaffold.RegularScaffold
import kotlinx.coroutines.delay
private const val TITLE = "Sample SwitchPreference"
@@ -88,13 +87,8 @@
}
}
- @Composable
- override fun Page(arguments: Bundle?) {
- RegularScaffold(title = TITLE) {
- for (entry in buildEntry(arguments)) {
- entry.UiLayout()
- }
- }
+ override fun getTitle(arguments: Bundle?): String {
+ return TITLE
}
}
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/TwoTargetSwitchPreferencePage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/TwoTargetSwitchPreferencePage.kt
index b991f59..22da99c 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/TwoTargetSwitchPreferencePage.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/TwoTargetSwitchPreferencePage.kt
@@ -34,7 +34,6 @@
import com.android.settingslib.spa.widget.preference.PreferenceModel
import com.android.settingslib.spa.widget.preference.SwitchPreferenceModel
import com.android.settingslib.spa.widget.preference.TwoTargetSwitchPreference
-import com.android.settingslib.spa.widget.scaffold.RegularScaffold
import kotlinx.coroutines.delay
private const val TITLE = "Sample TwoTargetSwitchPreference"
@@ -88,13 +87,8 @@
}
}
- @Composable
- override fun Page(arguments: Bundle?) {
- RegularScaffold(title = TITLE) {
- for (entry in buildEntry(arguments)) {
- entry.UiLayout()
- }
- }
+ override fun getTitle(arguments: Bundle?): String {
+ return TITLE
}
}
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/ui/CategoryPage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/ui/CategoryPage.kt
index a4713b9..d87cbe8 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/ui/CategoryPage.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/ui/CategoryPage.kt
@@ -48,41 +48,40 @@
}
}
+ override fun getTitle(arguments: Bundle?): String {
+ return TITLE
+ }
+
@Composable
override fun Page(arguments: Bundle?) {
- CategoryPage()
- }
-}
-
-@Composable
-private fun CategoryPage() {
- RegularScaffold(title = TITLE) {
- CategoryTitle("Category A")
- Preference(remember {
- object : PreferenceModel {
- override val title = "Preference 1"
- override val summary = stateOf("Summary 1")
- }
- })
- Preference(remember {
- object : PreferenceModel {
- override val title = "Preference 2"
- override val summary = stateOf("Summary 2")
- }
- })
- Category("Category B") {
+ RegularScaffold(title = getTitle(arguments)) {
+ CategoryTitle("Category A")
Preference(remember {
object : PreferenceModel {
- override val title = "Preference 3"
- override val summary = stateOf("Summary 3")
+ override val title = "Preference 1"
+ override val summary = stateOf("Summary 1")
}
})
Preference(remember {
object : PreferenceModel {
- override val title = "Preference 4"
- override val summary = stateOf("Summary 4")
+ override val title = "Preference 2"
+ override val summary = stateOf("Summary 2")
}
})
+ Category("Category B") {
+ Preference(remember {
+ object : PreferenceModel {
+ override val title = "Preference 3"
+ override val summary = stateOf("Summary 3")
+ }
+ })
+ Preference(remember {
+ object : PreferenceModel {
+ override val title = "Preference 4"
+ override val summary = stateOf("Summary 4")
+ }
+ })
+ }
}
}
}
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/ui/SpinnerPage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/ui/SpinnerPage.kt
index 03b72d3..ec2f436 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/ui/SpinnerPage.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/ui/SpinnerPage.kt
@@ -49,9 +49,13 @@
}
}
+ override fun getTitle(arguments: Bundle?): String {
+ return TITLE
+ }
+
@Composable
override fun Page(arguments: Bundle?) {
- RegularScaffold(title = TITLE) {
+ RegularScaffold(title = getTitle(arguments)) {
val selectedIndex = rememberSaveable { mutableStateOf(0) }
Spinner(
options = (1..3).map { "Option $it" },
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsPageProvider.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsPageProvider.kt
index f8963b2..151b50cd 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsPageProvider.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsPageProvider.kt
@@ -19,6 +19,7 @@
import android.os.Bundle
import androidx.compose.runtime.Composable
import androidx.navigation.NamedNavArgument
+import com.android.settingslib.spa.widget.scaffold.RegularScaffold
/**
* An SettingsPageProvider which is used to create Settings page instances.
@@ -36,13 +37,19 @@
val parameter: List<NamedNavArgument>
get() = emptyList()
- /** The [Composable] used to render this page. */
- @Composable
- fun Page(arguments: Bundle?)
+ fun getTitle(arguments: Bundle?): String = displayName ?: name
fun buildEntry(arguments: Bundle?): List<SettingsEntry> = emptyList()
- fun getTitle(arguments: Bundle?): String = displayName ?: name
+ /** The [Composable] used to render this page. */
+ @Composable
+ fun Page(arguments: Bundle?) {
+ RegularScaffold(title = getTitle(arguments)) {
+ for (entry in buildEntry(arguments)) {
+ entry.UiLayout()
+ }
+ }
+ }
}
fun SettingsPageProvider.createSettingsPage(arguments: Bundle? = null): SettingsPage {
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SpaEnvironment.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SpaEnvironment.kt
index 6073425..b831043 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SpaEnvironment.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SpaEnvironment.kt
@@ -59,7 +59,8 @@
val entryRepository = lazy { SettingsEntryRepository(pageProviderRepository.value) }
- val appContext: Context = context.applicationContext
+ // In Robolectric test, applicationContext is not available. Use context as fallback.
+ val appContext: Context = context.applicationContext ?: context
open val browseActivityClass: Class<out Activity>? = null
diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/util/ParameterTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/util/ParameterTest.kt
new file mode 100644
index 0000000..21ff085
--- /dev/null
+++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/util/ParameterTest.kt
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.spa.framework.util
+
+import androidx.core.os.bundleOf
+import androidx.navigation.NamedNavArgument
+import androidx.navigation.NavType
+import androidx.navigation.navArgument
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+
+class ParameterTest {
+ @Test
+ fun navRouteTest() {
+ val navArguments = listOf(
+ navArgument("string_param") { type = NavType.StringType },
+ navArgument("int_param") { type = NavType.IntType },
+ )
+
+ val route = navArguments.navRoute()
+ assertThat(route).isEqualTo("/{string_param}/{int_param}")
+ }
+
+ @Test
+ fun navLinkTest() {
+ val navArguments = listOf(
+ navArgument("string_param") { type = NavType.StringType },
+ navArgument("int_param") { type = NavType.IntType },
+ )
+
+ val unsetAllLink = navArguments.navLink()
+ assertThat(unsetAllLink).isEqualTo("/[unset]/[unset]")
+
+ val setAllLink = navArguments.navLink(
+ bundleOf(
+ "string_param" to "myStr",
+ "int_param" to 10,
+ )
+ )
+ assertThat(setAllLink).isEqualTo("/myStr/10")
+
+ val setUnknownLink = navArguments.navLink(
+ bundleOf(
+ "string_param" to "myStr",
+ "int_param" to 10,
+ "unknown_param" to "unknown",
+ )
+ )
+ assertThat(setUnknownLink).isEqualTo("/myStr/10")
+
+ val setWrongTypeLink = navArguments.navLink(
+ bundleOf(
+ "string_param" to "myStr",
+ "int_param" to "wrongStr",
+ )
+ )
+ assertThat(setWrongTypeLink).isEqualTo("/myStr/0")
+ }
+
+ @Test
+ fun normalizeTest() {
+ val emptyArguments = emptyList<NamedNavArgument>()
+ assertThat(emptyArguments.normalize()).isNull()
+
+ val navArguments = listOf(
+ navArgument("string_param") { type = NavType.StringType },
+ navArgument("int_param") { type = NavType.IntType },
+ navArgument("rt_param") { type = NavType.StringType },
+ )
+
+ val emptyParam = navArguments.normalize()
+ assertThat(emptyParam).isNotNull()
+ assertThat(emptyParam.toString()).isEqualTo(
+ "Bundle[{rt_param=null, unset_string_param=null, unset_int_param=null}]"
+ )
+
+ val setParialParam = navArguments.normalize(
+ bundleOf(
+ "string_param" to "myStr",
+ "rt_param" to "rtStr",
+ )
+ )
+ assertThat(setParialParam).isNotNull()
+ assertThat(setParialParam.toString()).isEqualTo(
+ "Bundle[{rt_param=null, string_param=myStr, unset_int_param=null}]"
+ )
+
+ val setAllParam = navArguments.normalize(
+ bundleOf(
+ "string_param" to "myStr",
+ "int_param" to 10,
+ "rt_param" to "rtStr",
+ )
+ )
+ assertThat(setAllParam).isNotNull()
+ assertThat(setAllParam.toString()).isEqualTo(
+ "Bundle[{rt_param=null, int_param=10, string_param=myStr}]"
+ )
+ }
+
+ @Test
+ fun getArgTest() {
+ val navArguments = listOf(
+ navArgument("string_param") { type = NavType.StringType },
+ navArgument("int_param") { type = NavType.IntType },
+ )
+
+ assertThat(
+ navArguments.getStringArg(
+ "string_param", bundleOf(
+ "string_param" to "myStr",
+ )
+ )
+ ).isEqualTo("myStr")
+
+ assertThat(
+ navArguments.getStringArg(
+ "string_param", bundleOf(
+ "string_param" to 10,
+ )
+ )
+ ).isNull()
+
+ assertThat(
+ navArguments.getStringArg(
+ "unknown_param", bundleOf(
+ "string_param" to "myStr",
+ )
+ )
+ ).isNull()
+
+ assertThat(navArguments.getStringArg("string_param")).isNull()
+
+ assertThat(
+ navArguments.getIntArg(
+ "int_param", bundleOf(
+ "int_param" to 10,
+ )
+ )
+ ).isEqualTo(10)
+
+ assertThat(
+ navArguments.getIntArg(
+ "int_param", bundleOf(
+ "int_param" to "10",
+ )
+ )
+ ).isEqualTo(0)
+
+ assertThat(
+ navArguments.getIntArg(
+ "unknown_param", bundleOf(
+ "int_param" to 10,
+ )
+ )
+ ).isNull()
+
+ assertThat(navArguments.getIntArg("int_param")).isNull()
+ }
+
+ @Test
+ fun isRuntimeParamTest() {
+ val regularParam = navArgument("regular_param") { type = NavType.StringType }
+ val rtParam = navArgument("rt_param") { type = NavType.StringType }
+ assertThat(regularParam.isRuntimeParam()).isFalse()
+ assertThat(rtParam.isRuntimeParam()).isTrue()
+ }
+}
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/framework/common/Contexts.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/framework/common/Contexts.kt
index fd723dd..bb1cd6e 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/framework/common/Contexts.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/framework/common/Contexts.kt
@@ -22,6 +22,7 @@
import android.app.usage.StorageStatsManager
import android.apphibernation.AppHibernationManager
import android.content.Context
+import android.content.pm.CrossProfileApps
import android.content.pm.verify.domain.DomainVerificationManager
import android.os.UserHandle
import android.os.UserManager
@@ -36,6 +37,9 @@
/** The [AppOpsManager] instance. */
val Context.appOpsManager get() = getSystemService(AppOpsManager::class.java)!!
+/** The [CrossProfileApps] instance. */
+val Context.crossProfileApps get() = getSystemService(CrossProfileApps::class.java)!!
+
/** The [DevicePolicyManager] instance. */
val Context.devicePolicyManager get() = getSystemService(DevicePolicyManager::class.java)!!
diff --git a/packages/SettingsLib/res/values-uz/strings.xml b/packages/SettingsLib/res/values-uz/strings.xml
index 1738e01..efb5eb9 100644
--- a/packages/SettingsLib/res/values-uz/strings.xml
+++ b/packages/SettingsLib/res/values-uz/strings.xml
@@ -548,7 +548,7 @@
<string name="shared_data_no_blobs_text" msgid="3108114670341737434">"Bu foydalanuvchining umumiy maʼlumotlari topilmadi."</string>
<string name="shared_data_query_failure_text" msgid="3489828881998773687">"Umumiy maʼlumotlarni yuklashda xatolik yuz berdi. Qayta urining."</string>
<string name="blob_id_text" msgid="8680078988996308061">"Umumiy maʼlumotlar identifikatori: <xliff:g id="BLOB_ID">%d</xliff:g>"</string>
- <string name="blob_expires_text" msgid="7882727111491739331">"Amal qilish muddati: <xliff:g id="DATE">%s</xliff:g>"</string>
+ <string name="blob_expires_text" msgid="7882727111491739331">"Muddati: <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="shared_data_delete_failure_text" msgid="3842701391009628947">"Umumiy maʼlumotlarni oʻchirishda xatolik yuz berdi."</string>
<string name="shared_data_no_accessors_dialog_text" msgid="8903738462570715315">"Bu umumiy maʼlumotlar yuzasidan kelgan soʻrov topilmadi. Oʻchirib tashlansinmi?"</string>
<string name="accessor_info_title" msgid="8289823651512477787">"Umumiy maʼlumotlar bor ilovalar"</string>
diff --git a/packages/SystemUI/ktfmt_includes.txt b/packages/SystemUI/ktfmt_includes.txt
index 0f037e4..06ea381 100644
--- a/packages/SystemUI/ktfmt_includes.txt
+++ b/packages/SystemUI/ktfmt_includes.txt
@@ -27,8 +27,6 @@
-packages/SystemUI/shared/src/com/android/systemui/shared/clocks/AnimatableClockView.kt
-packages/SystemUI/shared/src/com/android/systemui/shared/clocks/ClockRegistry.kt
-packages/SystemUI/shared/src/com/android/systemui/shared/clocks/DefaultClockProvider.kt
--packages/SystemUI/shared/src/com/android/systemui/shared/regionsampling/RegionDarkness.kt
--packages/SystemUI/shared/src/com/android/systemui/shared/regionsampling/RegionSamplingInstance.kt
-packages/SystemUI/shared/src/com/android/systemui/shared/rotation/FloatingRotationButtonPositionCalculator.kt
-packages/SystemUI/shared/src/com/android/systemui/shared/system/UncaughtExceptionPreHandlerManager.kt
-packages/SystemUI/shared/src/com/android/systemui/shared/system/smartspace/SmartspaceState.kt
@@ -683,8 +681,6 @@
-packages/SystemUI/tests/src/com/android/systemui/shared/animation/UnfoldConstantTranslateAnimatorTest.kt
-packages/SystemUI/tests/src/com/android/systemui/shared/animation/UnfoldMoveFromCenterAnimatorTest.kt
-packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt
--packages/SystemUI/tests/src/com/android/systemui/shared/navigationbar/RegionSamplingHelperTest.kt
--packages/SystemUI/tests/src/com/android/systemui/shared/regionsampling/RegionSamplingInstanceTest.kt
-packages/SystemUI/tests/src/com/android/systemui/shared/rotation/RotationButtonControllerTest.kt
-packages/SystemUI/tests/src/com/android/systemui/shared/system/UncaughtExceptionPreHandlerTest.kt
-packages/SystemUI/tests/src/com/android/systemui/smartspace/DreamSmartspaceControllerTest.kt
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml b/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml
index d64587d..c297149 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml
@@ -31,7 +31,8 @@
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
- android:paddingStart="@dimen/clock_padding_start" />
+ android:paddingStart="@dimen/clock_padding_start"
+ android:visibility="invisible" />
<FrameLayout
android:id="@+id/lockscreen_clock_view_large"
android:layout_width="match_parent"
diff --git a/packages/SystemUI/res-keyguard/values-af/strings.xml b/packages/SystemUI/res-keyguard/values-af/strings.xml
index d5552f6..1ff549e 100644
--- a/packages/SystemUI/res-keyguard/values-af/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-af/strings.xml
@@ -78,12 +78,9 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Patroon word vereis nadat toestel herbegin het"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"PIN word vereis nadat toestel herbegin het"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Wagwoord word vereis nadat toestel herbegin het"</string>
- <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
- <skip />
+ <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Gebruik eerder ’n patroon vir bykomende sekuriteit"</string>
+ <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Gebruik eerder ’n PIN vir bykomende sekuriteit"</string>
+ <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Gebruik eerder ’n wagwoord vir bykomende sekuriteit"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Toestel is deur administrateur gesluit"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Toestel is handmatig gesluit"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Nie herken nie"</string>
@@ -93,6 +90,5 @@
<string name="clock_title_default" msgid="6342735240617459864">"Verstek"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Borrel"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Analoog"</string>
- <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
- <skip />
+ <string name="keyguard_unlock_to_continue" msgid="7509503484250597743">"Ontsluit jou toestel om voort te gaan"</string>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-am/strings.xml b/packages/SystemUI/res-keyguard/values-am/strings.xml
index 533e5a2..f61c8cf 100644
--- a/packages/SystemUI/res-keyguard/values-am/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-am/strings.xml
@@ -78,12 +78,9 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"መሣሪያ ዳግም ከጀመረ በኋላ ሥርዓተ ጥለት ያስፈልጋል"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"መሣሪያ ዳግም ከተነሳ በኋላ ፒን ያስፈልጋል"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"መሣሪያ ዳግም ከጀመረ በኋላ የይለፍ ቃል ያስፈልጋል"</string>
- <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
- <skip />
+ <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"ለተጨማሪ ደህንነት በምትኩ ስርዓተ ጥለት ይጠቀሙ"</string>
+ <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"ለተጨማሪ ደህንነት በምትኩ ፒን ይጠቀሙ"</string>
+ <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"ለተጨማሪ ደህንነት በምትኩ የይለፍ ቃል ይጠቀሙ"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"መሣሪያ በአስተዳዳሪ ተቆልፏል"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"መሣሪያ በተጠቃሚው ራሱ ተቆልፏል"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"አልታወቀም"</string>
@@ -93,6 +90,5 @@
<string name="clock_title_default" msgid="6342735240617459864">"ነባሪ"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"አረፋ"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"አናሎግ"</string>
- <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
- <skip />
+ <string name="keyguard_unlock_to_continue" msgid="7509503484250597743">"ለመቀጠል መሣሪያዎን ይክፈቱ"</string>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-ar/strings.xml b/packages/SystemUI/res-keyguard/values-ar/strings.xml
index 81ce7d3..f3256ba 100644
--- a/packages/SystemUI/res-keyguard/values-ar/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ar/strings.xml
@@ -78,12 +78,9 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"يجب رسم النقش بعد إعادة تشغيل الجهاز"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"يجب إدخال رقم التعريف الشخصي بعد إعادة تشغيل الجهاز"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"يجب إدخال كلمة المرور بعد إعادة تشغيل الجهاز"</string>
- <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
- <skip />
+ <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"لمزيد من الأمان، استخدِم النقش بدلاً من ذلك."</string>
+ <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"لمزيد من الأمان، أدخِل رقم التعريف الشخصي بدلاً من ذلك."</string>
+ <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"لمزيد من الأمان، أدخِل كلمة المرور بدلاً من ذلك."</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"اختار المشرف قفل الجهاز"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"تم حظر الجهاز يدويًا"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"لم يتم التعرّف عليه."</string>
@@ -93,6 +90,5 @@
<string name="clock_title_default" msgid="6342735240617459864">"تلقائي"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"فقاعة"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"ساعة تقليدية"</string>
- <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
- <skip />
+ <string name="keyguard_unlock_to_continue" msgid="7509503484250597743">"يجب فتح قفل الجهاز للمتابعة"</string>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-as/strings.xml b/packages/SystemUI/res-keyguard/values-as/strings.xml
index 443f666..f9dc46f 100644
--- a/packages/SystemUI/res-keyguard/values-as/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-as/strings.xml
@@ -78,12 +78,9 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"ডিভাইচ ৰিষ্টাৰ্ট হোৱাৰ পাছত আৰ্হি দিয়াটো বাধ্যতামূলক"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"ডিভাইচ ৰিষ্টাৰ্ট হোৱাৰ পাছত পিন দিয়াটো বাধ্যতামূলক"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"ডিভাইচ ৰিষ্টাৰ্ট হোৱাৰ পাছত পাছৱৰ্ড দিয়াটো বাধ্যতামূলক"</string>
- <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
- <skip />
+ <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"অতিৰিক্ত সুৰক্ষাৰ বাবে, ইয়াৰ পৰিৱৰ্তে আৰ্হি ব্যৱহাৰ কৰক"</string>
+ <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"অতিৰিক্ত সুৰক্ষাৰ বাবে, ইয়াৰ পৰিৱৰ্তে পিন ব্যৱহাৰ কৰক"</string>
+ <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"অতিৰিক্ত সুৰক্ষাৰ বাবে, ইয়াৰ পৰিৱৰ্তে পাছৱৰ্ড ব্যৱহাৰ কৰক"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"প্ৰশাসকে ডিভাইচ লক কৰি ৰাখিছে"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"ডিভাইচটো মেনুৱেলভাৱে লক কৰা হৈছিল"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"চিনাক্ত কৰিব পৰা নাই"</string>
@@ -93,6 +90,5 @@
<string name="clock_title_default" msgid="6342735240617459864">"ডিফ’ল্ট"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"বাবল"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"এনাল’গ"</string>
- <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
- <skip />
+ <string name="keyguard_unlock_to_continue" msgid="7509503484250597743">"অব্যাহত ৰাখিবলৈ আপোনাৰ ডিভাইচটো আনলক কৰক"</string>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-az/strings.xml b/packages/SystemUI/res-keyguard/values-az/strings.xml
index e125697..65c1c93 100644
--- a/packages/SystemUI/res-keyguard/values-az/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-az/strings.xml
@@ -78,12 +78,9 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Cihaz yenidən başladıqdan sonra model tələb olunur"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Cihaz yeniden başladıqdan sonra PIN tələb olunur"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Cihaz yeniden başladıqdan sonra parol tələb olunur"</string>
- <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
- <skip />
+ <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Əlavə təhlükəsizlik üçün modeldən istifadə edin"</string>
+ <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Əlavə təhlükəsizlik üçün PIN istifadə edin"</string>
+ <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Əlavə təhlükəsizlik üçün paroldan istifadə edin"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Cihaz admin tərəfindən kilidlənib"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Cihaz əl ilə kilidləndi"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Tanınmır"</string>
@@ -93,6 +90,5 @@
<string name="clock_title_default" msgid="6342735240617459864">"Defolt"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Qabarcıq"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Analoq"</string>
- <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
- <skip />
+ <string name="keyguard_unlock_to_continue" msgid="7509503484250597743">"Davam etmək üçün cihazınızın kilidini açın"</string>
</resources>
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 f0d1ef2..cf363df 100644
--- a/packages/SystemUI/res-keyguard/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-b+sr+Latn/strings.xml
@@ -78,12 +78,9 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Treba da unesete šablon kada se uređaj ponovo pokrene"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Treba da unesete PIN kada se uređaj ponovo pokrene"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Treba da unesete lozinku kada se uređaj ponovo pokrene"</string>
- <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
- <skip />
+ <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Za dodatnu bezbednost koristite šablon"</string>
+ <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Za dodatnu bezbednost koristite PIN"</string>
+ <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Za dodatnu bezbednost koristite lozinku"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Administrator je zaključao uređaj"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Uređaj je ručno zaključan"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Nije prepoznat"</string>
@@ -93,6 +90,5 @@
<string name="clock_title_default" msgid="6342735240617459864">"Podrazumevani"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Mehurići"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Analogni"</string>
- <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
- <skip />
+ <string name="keyguard_unlock_to_continue" msgid="7509503484250597743">"Otključajte uređaj da biste nastavili"</string>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-be/strings.xml b/packages/SystemUI/res-keyguard/values-be/strings.xml
index e1af3ece..c2dedf30 100644
--- a/packages/SystemUI/res-keyguard/values-be/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-be/strings.xml
@@ -78,12 +78,9 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Пасля перазапуску прылады патрабуецца ўзор"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Пасля перазапуску прылады патрабуецца PIN-код"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Пасля перазапуску прылады патрабуецца пароль"</string>
- <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
- <skip />
+ <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"У мэтах дадатковай бяспекі скарыстайце ўзор разблакіроўкі"</string>
+ <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"У мэтах дадатковай бяспекі скарыстайце PIN-код"</string>
+ <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"У мэтах дадатковай бяспекі скарыстайце пароль"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Прылада заблакіравана адміністратарам"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Прылада была заблакіравана ўручную"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Не распазнана"</string>
@@ -93,6 +90,5 @@
<string name="clock_title_default" msgid="6342735240617459864">"Стандартны"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Бурбалкі"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Са стрэлкамі"</string>
- <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
- <skip />
+ <string name="keyguard_unlock_to_continue" msgid="7509503484250597743">"Каб працягнуць, разблакіруйце прыладу"</string>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-bg/strings.xml b/packages/SystemUI/res-keyguard/values-bg/strings.xml
index 0b4417a..546a645 100644
--- a/packages/SystemUI/res-keyguard/values-bg/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-bg/strings.xml
@@ -78,12 +78,9 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"След рестартиране на устройството се изисква фигура"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"След рестартиране на устройството се изисква ПИН код"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"След рестартиране на устройството се изисква парола"</string>
- <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
- <skip />
+ <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"За допълнителна сигурност използвайте фигура вместо това"</string>
+ <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"За допълнителна сигурност използвайте ПИН код вместо това"</string>
+ <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"За допълнителна сигурност използвайте парола вместо това"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Устройството е заключено от администратора"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Устройството бе заключено ръчно"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Не е разпознато"</string>
@@ -93,6 +90,5 @@
<string name="clock_title_default" msgid="6342735240617459864">"Стандартен"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Балонен"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Аналогов"</string>
- <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
- <skip />
+ <string name="keyguard_unlock_to_continue" msgid="7509503484250597743">"Отключете устройството си, за да продължите"</string>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-bn/strings.xml b/packages/SystemUI/res-keyguard/values-bn/strings.xml
index 4851579..7b3df35 100644
--- a/packages/SystemUI/res-keyguard/values-bn/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-bn/strings.xml
@@ -78,12 +78,9 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"ডিভাইসটি পুনরায় চালু হওয়ার পর প্যাটার্নের প্রয়োজন হবে"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"ডিভাইসটি পুনরায় চালু হওয়ার পর পিন প্রয়োজন হবে"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"ডিভাইসটি পুনরায় চালু হওয়ার পর পাসওয়ার্ডের প্রয়োজন হবে"</string>
- <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
- <skip />
+ <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"অতিরিক্ত সুরক্ষার জন্য, এর বদলে প্যাটার্ন ব্যবহার করুন"</string>
+ <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"অতিরিক্ত সুরক্ষার জন্য, এর বদলে পিন ব্যবহার করুন"</string>
+ <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"অতিরিক্ত সুরক্ষার জন্য, এর বদলে পাসওয়ার্ড ব্যবহার করুন"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"প্রশাসক ডিভাইসটি লক করেছেন"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"ডিভাইসটিকে ম্যানুয়ালি লক করা হয়েছে"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"শনাক্ত করা যায়নি"</string>
@@ -93,6 +90,5 @@
<string name="clock_title_default" msgid="6342735240617459864">"ডিফল্ট"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"বাবল"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"অ্যানালগ"</string>
- <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
- <skip />
+ <string name="keyguard_unlock_to_continue" msgid="7509503484250597743">"চালিয়ে যেতে আপনার ডিভাইস আনলক করুন"</string>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-bs/strings.xml b/packages/SystemUI/res-keyguard/values-bs/strings.xml
index 4705b4d9..bb9e690 100644
--- a/packages/SystemUI/res-keyguard/values-bs/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-bs/strings.xml
@@ -78,12 +78,9 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Potreban je uzorak nakon što se uređaj ponovo pokrene"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Potreban je PIN nakon što se uređaj ponovo pokrene"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Potrebna je lozinka nakon što se uređaj ponovo pokrene"</string>
- <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
- <skip />
+ <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Radi dodatne zaštite, umjesto toga koristite uzorak"</string>
+ <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Radi dodatne zaštite, umjesto toga koristite PIN"</string>
+ <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Radi dodatne zašitite, umjesto toga koristite lozinku"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Uređaj je zaključao administrator"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Uređaj je ručno zaključan"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Nije prepoznato"</string>
@@ -93,6 +90,5 @@
<string name="clock_title_default" msgid="6342735240617459864">"Zadano"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Mjehurići"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Analogni"</string>
- <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
- <skip />
+ <string name="keyguard_unlock_to_continue" msgid="7509503484250597743">"Otključajte uređaj da nastavite"</string>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-ca/strings.xml b/packages/SystemUI/res-keyguard/values-ca/strings.xml
index 284eaeb..1c81c60 100644
--- a/packages/SystemUI/res-keyguard/values-ca/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ca/strings.xml
@@ -78,12 +78,9 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Cal introduir el patró quan es reinicia el dispositiu"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Cal introduir el PIN quan es reinicia el dispositiu"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Cal introduir la contrasenya quan es reinicia el dispositiu"</string>
- <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
- <skip />
+ <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Per a més seguretat, utilitza el patró"</string>
+ <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Per a més seguretat, utilitza el PIN"</string>
+ <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Per a més seguretat, utilitza la contrasenya"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"L\'administrador ha bloquejat el dispositiu"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"El dispositiu s\'ha bloquejat manualment"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"No s\'ha reconegut"</string>
@@ -93,6 +90,5 @@
<string name="clock_title_default" msgid="6342735240617459864">"Predeterminada"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Bombolla"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Analògica"</string>
- <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
- <skip />
+ <string name="keyguard_unlock_to_continue" msgid="7509503484250597743">"Desbloqueja el dispositiu per continuar"</string>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-cs/strings.xml b/packages/SystemUI/res-keyguard/values-cs/strings.xml
index 6b4f607..9a6178c 100644
--- a/packages/SystemUI/res-keyguard/values-cs/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-cs/strings.xml
@@ -78,12 +78,9 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Po restartování zařízení je vyžadováno gesto"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Po restartování zařízení je vyžadován kód PIN"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Po restartování zařízení je vyžadováno heslo"</string>
- <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
- <skip />
+ <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Z bezpečnostních důvodů raději použijte gesto"</string>
+ <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Z bezpečnostních důvodů raději použijte PIN"</string>
+ <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Z bezpečnostních důvodů raději použijte heslo"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Zařízení je uzamknuto administrátorem"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Zařízení bylo ručně uzamčeno"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Nerozpoznáno"</string>
@@ -93,6 +90,5 @@
<string name="clock_title_default" msgid="6342735240617459864">"Výchozí"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Bublina"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Analogové"</string>
- <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
- <skip />
+ <string name="keyguard_unlock_to_continue" msgid="7509503484250597743">"Pokud chcete pokračovat, odemkněte zařízení"</string>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-da/strings.xml b/packages/SystemUI/res-keyguard/values-da/strings.xml
index 85238df..aac1b83 100644
--- a/packages/SystemUI/res-keyguard/values-da/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-da/strings.xml
@@ -78,12 +78,9 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Du skal angive et mønster, når du har genstartet enheden"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Der skal angives en pinkode efter genstart af enheden"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Der skal angives en adgangskode efter genstart af enheden"</string>
- <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
- <skip />
+ <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Øg sikkerheden ved at bruge dit oplåsningsmønter i stedet"</string>
+ <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Øg sikkerheden ved at bruge din pinkode i stedet"</string>
+ <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Øg sikkerheden ved at bruge din adgangskode i stedet"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Enheden er blevet låst af administratoren"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Enheden blev låst manuelt"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Ikke genkendt"</string>
@@ -93,6 +90,5 @@
<string name="clock_title_default" msgid="6342735240617459864">"Standard"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Boble"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Analog"</string>
- <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
- <skip />
+ <string name="keyguard_unlock_to_continue" msgid="7509503484250597743">"Lås din enhed op for at fortsætte"</string>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-de/strings.xml b/packages/SystemUI/res-keyguard/values-de/strings.xml
index 18befed..5a340ff 100644
--- a/packages/SystemUI/res-keyguard/values-de/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-de/strings.xml
@@ -78,12 +78,9 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Nach dem Neustart des Geräts ist die Eingabe des Musters erforderlich"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Nach dem Neustart des Geräts ist die Eingabe der PIN erforderlich"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Nach dem Neustart des Geräts ist die Eingabe des Passworts erforderlich"</string>
- <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
- <skip />
+ <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Verwende für mehr Sicherheit stattdessen dein Muster"</string>
+ <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Verwende für mehr Sicherheit stattdessen deine PIN"</string>
+ <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Verwende für mehr Sicherheit stattdessen dein Passwort"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Gerät vom Administrator gesperrt"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Gerät manuell gesperrt"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Nicht erkannt"</string>
@@ -93,6 +90,5 @@
<string name="clock_title_default" msgid="6342735240617459864">"Standard"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Bubble"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Analog"</string>
- <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
- <skip />
+ <string name="keyguard_unlock_to_continue" msgid="7509503484250597743">"Gerät entsperren, um fortzufahren"</string>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-el/strings.xml b/packages/SystemUI/res-keyguard/values-el/strings.xml
index 65b84486..973139f 100644
--- a/packages/SystemUI/res-keyguard/values-el/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-el/strings.xml
@@ -78,12 +78,9 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Απαιτείται μοτίβο μετά από την επανεκκίνηση της συσκευής"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Απαιτείται PIN μετά από την επανεκκίνηση της συσκευής"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Απαιτείται κωδικός πρόσβασης μετά από την επανεκκίνηση της συσκευής"</string>
- <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
- <skip />
+ <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Για πρόσθετη ασφάλεια, χρησιμοποιήστε εναλλακτικά μοτίβο"</string>
+ <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Για πρόσθετη ασφάλεια, χρησιμοποιήστε εναλλακτικά PIN"</string>
+ <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Για πρόσθετη ασφάλεια, χρησιμοποιήστε εναλλακτικά κωδικό πρόσβασης"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Η συσκευή κλειδώθηκε από τον διαχειριστή"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Η συσκευή κλειδώθηκε με μη αυτόματο τρόπο"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Δεν αναγνωρίστηκε"</string>
@@ -93,6 +90,5 @@
<string name="clock_title_default" msgid="6342735240617459864">"Προεπιλογή"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Συννεφάκι"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Αναλογικό"</string>
- <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
- <skip />
+ <string name="keyguard_unlock_to_continue" msgid="7509503484250597743">"Ξεκλειδώστε τη συσκευή σας για να συνεχίσετε"</string>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-en-rAU/strings.xml b/packages/SystemUI/res-keyguard/values-en-rAU/strings.xml
index 588f1b5..41eaa389 100644
--- a/packages/SystemUI/res-keyguard/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-en-rAU/strings.xml
@@ -78,12 +78,9 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Pattern required after device restarts"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"PIN required after device restarts"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Password required after device restarts"</string>
- <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
- <skip />
+ <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"For additional security, use pattern instead"</string>
+ <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"For additional security, use PIN instead"</string>
+ <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"For additional security, use password instead"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Device locked by admin"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Device was locked manually"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Not recognised"</string>
@@ -93,6 +90,5 @@
<string name="clock_title_default" msgid="6342735240617459864">"Default"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Bubble"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Analogue"</string>
- <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
- <skip />
+ <string name="keyguard_unlock_to_continue" msgid="7509503484250597743">"Unlock your device to continue"</string>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-en-rCA/strings.xml b/packages/SystemUI/res-keyguard/values-en-rCA/strings.xml
index 08fc8d6..c8ba237 100644
--- a/packages/SystemUI/res-keyguard/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-en-rCA/strings.xml
@@ -78,12 +78,9 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Pattern required after device restarts"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"PIN required after device restarts"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Password required after device restarts"</string>
- <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
- <skip />
+ <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"For additional security, use pattern instead"</string>
+ <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"For additional security, use PIN instead"</string>
+ <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"For additional security, use password instead"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Device locked by admin"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Device was locked manually"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Not recognised"</string>
@@ -93,6 +90,5 @@
<string name="clock_title_default" msgid="6342735240617459864">"Default"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Bubble"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Analogue"</string>
- <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
- <skip />
+ <string name="keyguard_unlock_to_continue" msgid="7509503484250597743">"Unlock your device to continue"</string>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-en-rGB/strings.xml b/packages/SystemUI/res-keyguard/values-en-rGB/strings.xml
index 588f1b5..41eaa389 100644
--- a/packages/SystemUI/res-keyguard/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-en-rGB/strings.xml
@@ -78,12 +78,9 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Pattern required after device restarts"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"PIN required after device restarts"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Password required after device restarts"</string>
- <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
- <skip />
+ <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"For additional security, use pattern instead"</string>
+ <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"For additional security, use PIN instead"</string>
+ <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"For additional security, use password instead"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Device locked by admin"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Device was locked manually"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Not recognised"</string>
@@ -93,6 +90,5 @@
<string name="clock_title_default" msgid="6342735240617459864">"Default"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Bubble"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Analogue"</string>
- <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
- <skip />
+ <string name="keyguard_unlock_to_continue" msgid="7509503484250597743">"Unlock your device to continue"</string>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-en-rIN/strings.xml b/packages/SystemUI/res-keyguard/values-en-rIN/strings.xml
index 588f1b5..41eaa389 100644
--- a/packages/SystemUI/res-keyguard/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-en-rIN/strings.xml
@@ -78,12 +78,9 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Pattern required after device restarts"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"PIN required after device restarts"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Password required after device restarts"</string>
- <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
- <skip />
+ <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"For additional security, use pattern instead"</string>
+ <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"For additional security, use PIN instead"</string>
+ <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"For additional security, use password instead"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Device locked by admin"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Device was locked manually"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Not recognised"</string>
@@ -93,6 +90,5 @@
<string name="clock_title_default" msgid="6342735240617459864">"Default"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Bubble"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Analogue"</string>
- <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
- <skip />
+ <string name="keyguard_unlock_to_continue" msgid="7509503484250597743">"Unlock your device to continue"</string>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-es-rUS/strings.xml b/packages/SystemUI/res-keyguard/values-es-rUS/strings.xml
index c71a678..6314d90 100644
--- a/packages/SystemUI/res-keyguard/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-es-rUS/strings.xml
@@ -78,12 +78,9 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Se requiere el patrón después de reiniciar el dispositivo"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Se requiere el PIN después de reiniciar el dispositivo"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Se requiere la contraseña después de reiniciar el dispositivo"</string>
- <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
- <skip />
+ <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Para seguridad adicional, usa un patrón"</string>
+ <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Para seguridad adicional, usa un PIN"</string>
+ <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Para seguridad adicional, usa una contraseña"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Dispositivo bloqueado por el administrador"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"El dispositivo se bloqueó de forma manual"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"No se reconoció"</string>
@@ -93,6 +90,5 @@
<string name="clock_title_default" msgid="6342735240617459864">"Predeterminado"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Burbuja"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Analógico"</string>
- <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
- <skip />
+ <string name="keyguard_unlock_to_continue" msgid="7509503484250597743">"Desbloquea tu dispositivo para continuar"</string>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-es/strings.xml b/packages/SystemUI/res-keyguard/values-es/strings.xml
index c6ee698..5aecf84 100644
--- a/packages/SystemUI/res-keyguard/values-es/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-es/strings.xml
@@ -78,12 +78,9 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Debes introducir el patrón después de reiniciar el dispositivo"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Debes introducir el PIN después de reiniciar el dispositivo"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Debes introducir la contraseña después de reiniciar el dispositivo"</string>
- <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
- <skip />
+ <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Para mayor seguridad, usa el patrón"</string>
+ <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Para mayor seguridad, usa el PIN"</string>
+ <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Para mayor seguridad, usa la contraseña"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Dispositivo bloqueado por el administrador"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"El dispositivo se ha bloqueado manualmente"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"No se reconoce"</string>
@@ -93,6 +90,5 @@
<string name="clock_title_default" msgid="6342735240617459864">"Predeterminado"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Burbuja"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Analógico"</string>
- <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
- <skip />
+ <string name="keyguard_unlock_to_continue" msgid="7509503484250597743">"Desbloquea tu dispositivo para continuar"</string>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-et/strings.xml b/packages/SystemUI/res-keyguard/values-et/strings.xml
index 071ede8..9306ff6 100644
--- a/packages/SystemUI/res-keyguard/values-et/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-et/strings.xml
@@ -78,12 +78,9 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Pärast seadme taaskäivitamist tuleb sisestada muster"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Pärast seadme taaskäivitamist tuleb sisestada PIN-kood"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Pärast seadme taaskäivitamist tuleb sisestada parool"</string>
- <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
- <skip />
+ <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Kasutage tugevama turvalisuse huvides hoopis mustrit"</string>
+ <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Kasutage tugevama turvalisuse huvides hoopis PIN-koodi"</string>
+ <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Kasutage tugevama turvalisuse huvides hoopis parooli"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Administraator lukustas seadme"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Seade lukustati käsitsi"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Ei tuvastatud"</string>
@@ -93,6 +90,5 @@
<string name="clock_title_default" msgid="6342735240617459864">"Vaikenumbrilaud"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Mull"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Analoog"</string>
- <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
- <skip />
+ <string name="keyguard_unlock_to_continue" msgid="7509503484250597743">"Jätkamiseks avage oma seade"</string>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-eu/strings.xml b/packages/SystemUI/res-keyguard/values-eu/strings.xml
index 9b8e65b..4ebe0f0 100644
--- a/packages/SystemUI/res-keyguard/values-eu/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-eu/strings.xml
@@ -78,12 +78,9 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Eredua marraztu beharko duzu gailua berrabiarazten denean"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"PINa idatzi beharko duzu gailua berrabiarazten denean"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Pasahitza idatzi beharko duzu gailua berrabiarazten denean"</string>
- <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
- <skip />
+ <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Babestuago egoteko, erabili eredua"</string>
+ <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Babestuago egoteko, erabili PINa"</string>
+ <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Babestuago egoteko, erabili pasahitza"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Administratzaileak blokeatu egin du gailua"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Eskuz blokeatu da gailua"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Ez da ezagutu"</string>
@@ -93,6 +90,5 @@
<string name="clock_title_default" msgid="6342735240617459864">"Lehenetsia"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Puxikak"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Analogikoa"</string>
- <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
- <skip />
+ <string name="keyguard_unlock_to_continue" msgid="7509503484250597743">"Aurrera egiteko, desblokeatu gailua"</string>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-fa/strings.xml b/packages/SystemUI/res-keyguard/values-fa/strings.xml
index 3583f1e..e9a2e87 100644
--- a/packages/SystemUI/res-keyguard/values-fa/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-fa/strings.xml
@@ -78,12 +78,9 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"بعد از بازنشانی دستگاه باید الگو وارد شود"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"بعد از بازنشانی دستگاه باید پین وارد شود"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"بعد از بازنشانی دستگاه باید گذرواژه وارد شود"</string>
- <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
- <skip />
+ <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"برای امنیت بیشتر، بهجای آن از الگو استفاده کنید"</string>
+ <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"برای امنیت بیشتر، بهجای آن از پین استفاده کنید"</string>
+ <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"برای امنیت بیشتر، بهجای آن از گذرواژه استفاده کنید"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"دستگاه توسط سرپرست سیستم قفل شده است"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"دستگاه بهصورت دستی قفل شده است"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"شناسایی نشد"</string>
@@ -93,6 +90,5 @@
<string name="clock_title_default" msgid="6342735240617459864">"پیشفرض"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"حباب"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"آنالوگ"</string>
- <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
- <skip />
+ <string name="keyguard_unlock_to_continue" msgid="7509503484250597743">"برای ادامه، قفل دستگاهتان را باز کنید"</string>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-fi/strings.xml b/packages/SystemUI/res-keyguard/values-fi/strings.xml
index a0ac6df..e80869a 100644
--- a/packages/SystemUI/res-keyguard/values-fi/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-fi/strings.xml
@@ -78,12 +78,9 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Kuvio vaaditaan laitteen uudelleenkäynnistyksen jälkeen."</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"PIN-koodi vaaditaan laitteen uudelleenkäynnistyksen jälkeen."</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Salasana vaaditaan laitteen uudelleenkäynnistyksen jälkeen."</string>
- <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
- <skip />
+ <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Lisäsuojaa saat, kun käytät sen sijaan kuviota"</string>
+ <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Lisäsuojaa saat, kun käytät sen sijaan PIN-koodia"</string>
+ <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Lisäsuojaa saat, kun käytät sen sijaan salasanaa"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Järjestelmänvalvoja lukitsi laitteen."</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Laite lukittiin manuaalisesti"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Ei tunnistettu"</string>
@@ -93,6 +90,5 @@
<string name="clock_title_default" msgid="6342735240617459864">"Oletus"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Kupla"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Analoginen"</string>
- <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
- <skip />
+ <string name="keyguard_unlock_to_continue" msgid="7509503484250597743">"Jatka avaamalla laitteen lukitus"</string>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-fr/strings.xml b/packages/SystemUI/res-keyguard/values-fr/strings.xml
index ec00ba3..92d0617 100644
--- a/packages/SystemUI/res-keyguard/values-fr/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-fr/strings.xml
@@ -78,12 +78,9 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Veuillez dessiner le schéma après le redémarrage de l\'appareil"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Veuillez saisir le code après le redémarrage de l\'appareil"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Veuillez saisir le mot de passe après le redémarrage de l\'appareil"</string>
- <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
- <skip />
+ <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Pour plus de sécurité, utilisez plutôt un schéma"</string>
+ <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Pour plus de sécurité, utilisez plutôt un code"</string>
+ <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Pour plus de sécurité, utilisez plutôt un mot de passe"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Appareil verrouillé par l\'administrateur"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Appareil verrouillé manuellement"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Non reconnu"</string>
@@ -93,6 +90,5 @@
<string name="clock_title_default" msgid="6342735240617459864">"Par défaut"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Bulle"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Analogique"</string>
- <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
- <skip />
+ <string name="keyguard_unlock_to_continue" msgid="7509503484250597743">"Déverrouillez votre appareil pour continuer"</string>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-gl/strings.xml b/packages/SystemUI/res-keyguard/values-gl/strings.xml
index a3f8e86..776e90a 100644
--- a/packages/SystemUI/res-keyguard/values-gl/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-gl/strings.xml
@@ -78,12 +78,9 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"É necesario o padrón despois do reinicio do dispositivo"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"É necesario o PIN despois do reinicio do dispositivo"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"É necesario o contrasinal despois do reinicio do dispositivo"</string>
- <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
- <skip />
+ <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Utiliza un padrón para obter maior seguranza"</string>
+ <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Utiliza un PIN para obter maior seguranza"</string>
+ <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Utiliza un contrasinal para obter maior seguranza"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"O administrador bloqueou o dispositivo"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"O dispositivo bloqueouse manualmente"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Non se recoñeceu"</string>
@@ -93,6 +90,5 @@
<string name="clock_title_default" msgid="6342735240617459864">"Predeterminado"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Burbulla"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Analóxico"</string>
- <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
- <skip />
+ <string name="keyguard_unlock_to_continue" msgid="7509503484250597743">"Desbloquea o dispositivo para continuar"</string>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-gu/strings.xml b/packages/SystemUI/res-keyguard/values-gu/strings.xml
index c97fe01..a8b9a3a 100644
--- a/packages/SystemUI/res-keyguard/values-gu/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-gu/strings.xml
@@ -78,12 +78,9 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"ઉપકરણનો પુનઃપ્રારંભ થાય તે પછી પૅટર્ન જરૂરી છે"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"ઉપકરણનો પુનઃપ્રારંભ થાય તે પછી પિન જરૂરી છે"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"ઉપકરણનો પુનઃપ્રારંભ થાય તે પછી પાસવર્ડ જરૂરી છે"</string>
- <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
- <skip />
+ <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"વધારાની સુરક્ષા માટે, તેના બદલે પૅટર્નનો ઉપયોગ કરો"</string>
+ <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"વધારાની સુરક્ષા માટે, તેના બદલે પિનનો ઉપયોગ કરો"</string>
+ <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"વધારાની સુરક્ષા માટે, તેના બદલે પાસવર્ડનો ઉપયોગ કરો"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"વ્યવસ્થાપકે ઉપકરણ લૉક કરેલું છે"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"ઉપકરણ મેન્યુઅલી લૉક કર્યું હતું"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"ઓળખાયેલ નથી"</string>
@@ -93,6 +90,5 @@
<string name="clock_title_default" msgid="6342735240617459864">"ડિફૉલ્ટ"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"બબલ"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"એનાલોગ"</string>
- <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
- <skip />
+ <string name="keyguard_unlock_to_continue" msgid="7509503484250597743">"ચાલુ રાખવા માટે તમારા ડિવાઇસને અનલૉક કરો"</string>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-hi/strings.xml b/packages/SystemUI/res-keyguard/values-hi/strings.xml
index 1283004..47560dd 100644
--- a/packages/SystemUI/res-keyguard/values-hi/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-hi/strings.xml
@@ -78,12 +78,9 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"डिवाइस फिर से चालू होने के बाद पैटर्न ज़रूरी है"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"डिवाइस फिर से चालू होने के बाद पिन ज़रूरी है"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"डिवाइस फिर से चालू होने के बाद पासवर्ड ज़रूरी है"</string>
- <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
- <skip />
+ <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"ज़्यादा सुरक्षा के लिए, इसके बजाय पैटर्न का इस्तेमाल करें"</string>
+ <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"ज़्यादा सुरक्षा के लिए, इसके बजाय पिन का इस्तेमाल करें"</string>
+ <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"ज़्यादा सुरक्षा के लिए, इसके बजाय पासवर्ड का इस्तेमाल करें"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"व्यवस्थापक ने डिवाइस को लॉक किया है"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"डिवाइस को मैन्युअल रूप से लॉक किया गया था"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"पहचान नहीं हो पाई"</string>
@@ -93,6 +90,5 @@
<string name="clock_title_default" msgid="6342735240617459864">"डिफ़ॉल्ट"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"बबल"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"एनालॉग"</string>
- <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
- <skip />
+ <string name="keyguard_unlock_to_continue" msgid="7509503484250597743">"जारी रखने के लिए डिवाइस अनलॉक करें"</string>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-hr/strings.xml b/packages/SystemUI/res-keyguard/values-hr/strings.xml
index 7a14a80..efd1cbb 100644
--- a/packages/SystemUI/res-keyguard/values-hr/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-hr/strings.xml
@@ -78,12 +78,9 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Nakon ponovnog pokretanja uređaja morate unijeti uzorak"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Nakon ponovnog pokretanja uređaja morate unijeti PIN"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Nakon ponovnog pokretanja uređaja morate unijeti zaporku"</string>
- <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
- <skip />
+ <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Za dodatnu sigurnost upotrijebite uzorak"</string>
+ <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Za dodatnu sigurnost upotrijebite PIN"</string>
+ <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Za dodatnu sigurnost upotrijebite zaporku"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Administrator je zaključao uređaj"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Uređaj je ručno zaključan"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Nije prepoznato"</string>
@@ -93,6 +90,5 @@
<string name="clock_title_default" msgid="6342735240617459864">"Zadano"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Mjehurić"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Analogni"</string>
- <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
- <skip />
+ <string name="keyguard_unlock_to_continue" msgid="7509503484250597743">"Otključajte uređaj da biste nastavili"</string>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-hu/strings.xml b/packages/SystemUI/res-keyguard/values-hu/strings.xml
index a4fbf53..0421ff8 100644
--- a/packages/SystemUI/res-keyguard/values-hu/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-hu/strings.xml
@@ -78,12 +78,9 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Az eszköz újraindítását követően meg kell adni a mintát"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Az eszköz újraindítását követően meg kell adni a PIN-kódot"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Az eszköz újraindítását követően meg kell adni a jelszót"</string>
- <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
- <skip />
+ <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"A nagyobb biztonság érdekében használjon inkább mintát"</string>
+ <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"A nagyobb biztonság érdekében használjon inkább PIN-kódot"</string>
+ <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"A nagyobb biztonság érdekében használjon inkább jelszót"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"A rendszergazda zárolta az eszközt"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Az eszközt manuálisan lezárták"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Nem ismerhető fel"</string>
@@ -93,6 +90,5 @@
<string name="clock_title_default" msgid="6342735240617459864">"Alapértelmezett"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Buborék"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Analóg"</string>
- <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
- <skip />
+ <string name="keyguard_unlock_to_continue" msgid="7509503484250597743">"A folytatáshoz oldja fel az eszközét"</string>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-hy/strings.xml b/packages/SystemUI/res-keyguard/values-hy/strings.xml
index 086eeb9..d421c29 100644
--- a/packages/SystemUI/res-keyguard/values-hy/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-hy/strings.xml
@@ -78,12 +78,9 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Սարքը վերագործարկելուց հետո անհրաժեշտ է մուտքագրել նախշը"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Սարքը վերագործարկելուց հետո անհրաժեշտ է մուտքագրել PIN կոդը"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Սարքը վերագործարկելուց հետո անհրաժեշտ է մուտքագրել գաղտնաբառը"</string>
- <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
- <skip />
+ <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Լրացուցիչ անվտանգության համար օգտագործեք նախշ"</string>
+ <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Լրացուցիչ անվտանգության համար օգտագործեք PIN կոդ"</string>
+ <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Լրացուցիչ անվտանգության համար օգտագործեք գաղտնաբառ"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Սարքը կողպված է ադմինիստրատորի կողմից"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Սարքը կողպվել է ձեռքով"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Չհաջողվեց ճանաչել"</string>
@@ -93,6 +90,5 @@
<string name="clock_title_default" msgid="6342735240617459864">"Կանխադրված"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Պղպջակ"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Անալոգային"</string>
- <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
- <skip />
+ <string name="keyguard_unlock_to_continue" msgid="7509503484250597743">"Շարունակելու համար ապակողպեք ձեր սարքը"</string>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-in/strings.xml b/packages/SystemUI/res-keyguard/values-in/strings.xml
index b43a032..2061e85 100644
--- a/packages/SystemUI/res-keyguard/values-in/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-in/strings.xml
@@ -78,12 +78,9 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Pola diperlukan setelah perangkat dimulai ulang"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"PIN diperlukan setelah perangkat dimulai ulang"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Sandi diperlukan setelah perangkat dimulai ulang"</string>
- <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
- <skip />
+ <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Untuk keamanan tambahan, gunakan pola"</string>
+ <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Untuk keamanan tambahan, gunakan PIN"</string>
+ <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Untuk keamanan tambahan, gunakan sandi"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Perangkat dikunci oleh admin"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Perangkat dikunci secara manual"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Tidak dikenali"</string>
@@ -93,6 +90,5 @@
<string name="clock_title_default" msgid="6342735240617459864">"Default"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Balon"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Analog"</string>
- <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
- <skip />
+ <string name="keyguard_unlock_to_continue" msgid="7509503484250597743">"Buka kunci perangkat untuk melanjutkan"</string>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-is/strings.xml b/packages/SystemUI/res-keyguard/values-is/strings.xml
index 8bad961..ae3da57 100644
--- a/packages/SystemUI/res-keyguard/values-is/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-is/strings.xml
@@ -78,12 +78,9 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Mynsturs er krafist þegar tækið er endurræst"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"PIN-númers er krafist þegar tækið er endurræst"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Aðgangsorðs er krafist þegar tækið er endurræst"</string>
- <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
- <skip />
+ <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Fyrir aukið öryggi skaltu nota mynstur í staðinn"</string>
+ <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Fyrir aukið öryggi skaltu nota PIN-númer í staðinn"</string>
+ <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Fyrir aukið öryggi skaltu nota aðgangsorð í staðinn"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Kerfisstjóri læsti tæki"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Tækinu var læst handvirkt"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Þekktist ekki"</string>
@@ -93,6 +90,5 @@
<string name="clock_title_default" msgid="6342735240617459864">"Sjálfgefið"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Blaðra"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Með vísum"</string>
- <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
- <skip />
+ <string name="keyguard_unlock_to_continue" msgid="7509503484250597743">"Taktu tækið úr lás til að halda áfram"</string>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-it/strings.xml b/packages/SystemUI/res-keyguard/values-it/strings.xml
index 186177ff..d1feea6 100644
--- a/packages/SystemUI/res-keyguard/values-it/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-it/strings.xml
@@ -78,12 +78,9 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Sequenza obbligatoria dopo il riavvio del dispositivo"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"PIN obbligatorio dopo il riavvio del dispositivo"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Password obbligatoria dopo il riavvio del dispositivo"</string>
- <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
- <skip />
+ <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Per maggior sicurezza, usa invece la sequenza"</string>
+ <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Per maggior sicurezza, usa invece il PIN"</string>
+ <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Per maggior sicurezza, usa invece la password"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Dispositivo bloccato dall\'amministratore"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Il dispositivo è stato bloccato manualmente"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Non riconosciuto"</string>
@@ -93,6 +90,5 @@
<string name="clock_title_default" msgid="6342735240617459864">"Predefinito"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Bolla"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Analogico"</string>
- <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
- <skip />
+ <string name="keyguard_unlock_to_continue" msgid="7509503484250597743">"Sblocca il dispositivo per continuare"</string>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-ka/strings.xml b/packages/SystemUI/res-keyguard/values-ka/strings.xml
index 123cc39..b56042a0 100644
--- a/packages/SystemUI/res-keyguard/values-ka/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ka/strings.xml
@@ -78,12 +78,9 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"მოწყობილობის გადატვირთვის შემდეგ საჭიროა ნიმუშის დახატვა"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"მოწყობილობის გადატვირთვის შემდეგ საჭიროა PIN-კოდის შეყვანა"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"მოწყობილობის გადატვირთვის შემდეგ საჭიროა პაროლის შეყვანა"</string>
- <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
- <skip />
+ <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"დამატებითი უსაფრთხოებისთვის გამოიყენეთ ნიმუში"</string>
+ <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"დამატებითი უსაფრთხოებისთვის გამოიყენეთ PIN"</string>
+ <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"დამატებითი უსაფრთხოებისთვის გამოიყენეთ პაროლი"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"მოწყობილობა ჩაკეტილია ადმინისტრატორის მიერ"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"მოწყობილობა ხელით ჩაიკეტა"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"არ არის ამოცნობილი"</string>
@@ -93,6 +90,5 @@
<string name="clock_title_default" msgid="6342735240617459864">"ნაგულისხმევი"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"ბუშტი"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"ანალოგური"</string>
- <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
- <skip />
+ <string name="keyguard_unlock_to_continue" msgid="7509503484250597743">"გასაგრძელებლად განბლოკეთ თქვენი მოწყობილობა"</string>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-kk/strings.xml b/packages/SystemUI/res-keyguard/values-kk/strings.xml
index 8daca5c..a4024de 100644
--- a/packages/SystemUI/res-keyguard/values-kk/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-kk/strings.xml
@@ -78,12 +78,9 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Құрылғы қайта іске қосылғаннан кейін, өрнекті енгізу қажет"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Құрылғы қайта іске қосылғаннан кейін, PIN кодын енгізу қажет"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Құрылғы қайта іске қосылғаннан кейін, құпия сөзді енгізу қажет"</string>
- <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
- <skip />
+ <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Қосымша қауіпсіздік үшін өрнекті пайдаланыңыз."</string>
+ <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Қосымша қауіпсіздік үшін PIN кодын пайдаланыңыз."</string>
+ <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Қосымша қауіпсіздік үшін құпия сөзді пайдаланыңыз."</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Құрылғыны әкімші құлыптаған"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Құрылғы қолмен құлыпталды"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Танылмады"</string>
@@ -93,6 +90,5 @@
<string name="clock_title_default" msgid="6342735240617459864">"Әдепкі"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Көпіршік"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Аналогтық"</string>
- <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
- <skip />
+ <string name="keyguard_unlock_to_continue" msgid="7509503484250597743">"Жалғастыру үшін құрылғының құлпын ашыңыз"</string>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-km/strings.xml b/packages/SystemUI/res-keyguard/values-km/strings.xml
index 73f507c..329912ab 100644
--- a/packages/SystemUI/res-keyguard/values-km/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-km/strings.xml
@@ -78,12 +78,9 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"តម្រូវឲ្យប្រើលំនាំ បន្ទាប់ពីឧបករណ៍ចាប់ផ្តើមឡើងវិញ"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"តម្រូវឲ្យបញ្ចូលកូដ PIN បន្ទាប់ពីឧបករណ៍ចាប់ផ្តើមឡើងវិញ"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"តម្រូវឲ្យបញ្ចូលពាក្យសម្ងាត់ បន្ទាប់ពីឧបករណ៍ចាប់ផ្តើមឡើងវិញ"</string>
- <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
- <skip />
+ <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"ដើម្បីសុវត្ថិភាពបន្ថែម សូមប្រើលំនាំជំនួសវិញ"</string>
+ <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"ដើម្បីសុវត្ថិភាពបន្ថែម សូមប្រើកូដ PIN ជំនួសវិញ"</string>
+ <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"ដើម្បីសុវត្ថិភាពបន្ថែម សូមប្រើពាក្យសម្ងាត់ជំនួសវិញ"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"ឧបករណ៍ត្រូវបានចាក់សោដោយអ្នកគ្រប់គ្រង"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"ឧបករណ៍ត្រូវបានចាក់សោដោយអ្នកប្រើផ្ទាល់"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"មិនអាចសម្គាល់បានទេ"</string>
@@ -93,6 +90,5 @@
<string name="clock_title_default" msgid="6342735240617459864">"លំនាំដើម"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"ពពុះ"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"អាណាឡូក"</string>
- <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
- <skip />
+ <string name="keyguard_unlock_to_continue" msgid="7509503484250597743">"ដោះសោឧបករណ៍របស់អ្នកដើម្បីបន្ត"</string>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-kn/strings.xml b/packages/SystemUI/res-keyguard/values-kn/strings.xml
index c279cea..d42d08d 100644
--- a/packages/SystemUI/res-keyguard/values-kn/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-kn/strings.xml
@@ -78,12 +78,9 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"ಸಾಧನ ಮರುಪ್ರಾರಂಭಗೊಂಡ ನಂತರ ಪ್ಯಾಟರ್ನ್ ಅಗತ್ಯವಿರುತ್ತದೆ"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"ಸಾಧನ ಮರುಪ್ರಾರಂಭಗೊಂಡ ನಂತರ ಪಿನ್ ಅಗತ್ಯವಿರುತ್ತದೆ"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"ಸಾಧನ ಮರುಪ್ರಾರಂಭಗೊಂಡ ನಂತರ ಪಾಸ್ವರ್ಡ್ ಅಗತ್ಯವಿರುತ್ತದೆ"</string>
- <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
- <skip />
+ <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"ಹೆಚ್ಚುವರಿ ಭದ್ರತೆಗಾಗಿ, ಬದಲಿಗೆ ಪ್ಯಾಟರ್ನ್ ಅನ್ನು ಬಳಸಿ"</string>
+ <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"ಹೆಚ್ಚುವರಿ ಭದ್ರತೆಗಾಗಿ, ಬದಲಿಗೆ ಪಿನ್ ಬಳಸಿ"</string>
+ <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"ಹೆಚ್ಚುವರಿ ಭದ್ರತೆಗಾಗಿ, ಬದಲಿಗೆ ಪಾಸ್ವರ್ಡ್ ಅನ್ನು ಬಳಸಿ"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"ನಿರ್ವಾಹಕರು ಸಾಧನವನ್ನು ಲಾಕ್ ಮಾಡಿದ್ದಾರೆ"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"ಸಾಧನವನ್ನು ಹಸ್ತಚಾಲಿತವಾಗಿ ಲಾಕ್ ಮಾಡಲಾಗಿದೆ"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"ಗುರುತಿಸಲಾಗಿಲ್ಲ"</string>
@@ -93,6 +90,5 @@
<string name="clock_title_default" msgid="6342735240617459864">"ಡೀಫಾಲ್ಟ್"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"ಬಬಲ್"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"ಅನಲಾಗ್"</string>
- <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
- <skip />
+ <string name="keyguard_unlock_to_continue" msgid="7509503484250597743">"ಮುಂದುವರಿಸಲು, ನಿಮ್ಮ ಸಾಧನವನ್ನು ಅನ್ಲಾಕ್ ಮಾಡಿ"</string>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-ko/strings.xml b/packages/SystemUI/res-keyguard/values-ko/strings.xml
index 4c058ed..e916fee 100644
--- a/packages/SystemUI/res-keyguard/values-ko/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ko/strings.xml
@@ -78,12 +78,9 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"기기가 다시 시작되면 패턴이 필요합니다."</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"기기가 다시 시작되면 PIN이 필요합니다."</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"기기가 다시 시작되면 비밀번호가 필요합니다."</string>
- <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
- <skip />
+ <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"보안 강화를 위해 대신 패턴 사용"</string>
+ <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"보안 강화를 위해 대신 PIN 사용"</string>
+ <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"보안 강화를 위해 대신 비밀번호 사용"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"관리자가 기기를 잠갔습니다."</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"기기가 수동으로 잠금 설정되었습니다."</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"인식할 수 없음"</string>
@@ -93,6 +90,5 @@
<string name="clock_title_default" msgid="6342735240617459864">"기본"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"버블"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"아날로그"</string>
- <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
- <skip />
+ <string name="keyguard_unlock_to_continue" msgid="7509503484250597743">"기기를 잠금 해제하여 계속"</string>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-ky/strings.xml b/packages/SystemUI/res-keyguard/values-ky/strings.xml
index 7c7099e..88abd1e 100644
--- a/packages/SystemUI/res-keyguard/values-ky/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ky/strings.xml
@@ -78,12 +78,9 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Түзмөк кайра күйгүзүлгөндөн кийин графикалык ачкычты тартуу талап кылынат"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Түзмөк кайра күйгүзүлгөндөн кийин PIN-кодду киргизүү талап кылынат"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Түзмөк кайра күйгүзүлгөндөн кийин сырсөздү киргизүү талап кылынат"</string>
- <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
- <skip />
+ <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Кошумча коопсуздук үчүн анын ордуна графикалык ачкычты колдонуңуз"</string>
+ <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Кошумча коопсуздук үчүн анын ордуна PIN кодду колдонуңуз"</string>
+ <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Кошумча коопсуздук үчүн анын ордуна сырсөздү колдонуңуз"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Түзмөктү администратор кулпулап койгон"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Түзмөк кол менен кулпуланды"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Таанылган жок"</string>
@@ -93,6 +90,5 @@
<string name="clock_title_default" msgid="6342735240617459864">"Демейки"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Көбүк"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Аналог"</string>
- <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
- <skip />
+ <string name="keyguard_unlock_to_continue" msgid="7509503484250597743">"Улантуу үчүн түзмөгүңүздүн кулпусун ачыңыз"</string>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-lo/strings.xml b/packages/SystemUI/res-keyguard/values-lo/strings.xml
index 5a6df42..5001c30 100644
--- a/packages/SystemUI/res-keyguard/values-lo/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-lo/strings.xml
@@ -78,12 +78,9 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"ຈຳເປັນຕ້ອງມີແບບຮູບປົດລັອກຫຼັງຈາກອຸປະກອນເລີ່ມລະບົບໃໝ່"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"ຈຳເປັນຕ້ອງມີ PIN ຫຼັງຈາກອຸປະກອນເລີ່ມລະບົບໃໝ່"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"ຈຳເປັນຕ້ອງມີລະຫັດຜ່ານຫຼັງຈາກອຸປະກອນເລີ່ມລະບົບໃໝ່"</string>
- <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
- <skip />
+ <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"ເພື່ອຄວາມປອດໄພເພີ່ມເຕີມ, ໃຫ້ໃຊ້ຮູບແບບແທນ"</string>
+ <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"ເພື່ອຄວາມປອດໄພເພີ່ມເຕີມ, ໃຫ້ໃຊ້ PIN ແທນ"</string>
+ <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"ເພື່ອຄວາມປອດໄພເພີ່ມເຕີມ, ໃຫ້ໃຊ້ລະຫັດຜ່ານແທນ"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"ອຸປະກອນຖືກລັອກໂດຍຜູ້ເບິ່ງແຍງລະບົບ"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"ອຸປະກອນຖືກສັ່ງໃຫ້ລັອກ"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"ບໍ່ຮູ້ຈັກ"</string>
@@ -93,6 +90,5 @@
<string name="clock_title_default" msgid="6342735240617459864">"ຄ່າເລີ່ມຕົ້ນ"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"ຟອງ"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"ໂມງເຂັມ"</string>
- <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
- <skip />
+ <string name="keyguard_unlock_to_continue" msgid="7509503484250597743">"ປົດລັອກອຸປະກອນຂອງທ່ານເພື່ອສືບຕໍ່"</string>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-lt/strings.xml b/packages/SystemUI/res-keyguard/values-lt/strings.xml
index 4d98fd1..20f6ad2 100644
--- a/packages/SystemUI/res-keyguard/values-lt/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-lt/strings.xml
@@ -78,12 +78,9 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Iš naujo paleidus įrenginį būtinas atrakinimo piešinys"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Iš naujo paleidus įrenginį būtinas PIN kodas"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Iš naujo paleidus įrenginį būtinas slaptažodis"</string>
- <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
- <skip />
+ <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Papildomai saugai užtikrinti geriau naudokite atrakinimo piešinį"</string>
+ <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Papildomai saugai užtikrinti geriau naudokite PIN kodą"</string>
+ <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Papildomai saugai užtikrinti geriau naudokite slaptažodį"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Įrenginį užrakino administratorius"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Įrenginys užrakintas neautomatiškai"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Neatpažinta"</string>
@@ -93,6 +90,5 @@
<string name="clock_title_default" msgid="6342735240617459864">"Numatytasis"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Debesėlis"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Analoginis"</string>
- <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
- <skip />
+ <string name="keyguard_unlock_to_continue" msgid="7509503484250597743">"Įrenginio atrakinimas norint tęsti"</string>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-lv/strings.xml b/packages/SystemUI/res-keyguard/values-lv/strings.xml
index 2660a06..7012c16 100644
--- a/packages/SystemUI/res-keyguard/values-lv/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-lv/strings.xml
@@ -78,12 +78,9 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Pēc ierīces restartēšanas ir jāievada atbloķēšanas kombinācija."</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Pēc ierīces restartēšanas ir jāievada PIN kods."</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Pēc ierīces restartēšanas ir jāievada parole."</string>
- <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
- <skip />
+ <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Papildu drošībai izmantojiet kombināciju"</string>
+ <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Papildu drošībai izmantojiet PIN"</string>
+ <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Papildu drošībai izmantojiet paroli"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Administrators bloķēja ierīci."</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Ierīce tika bloķēta manuāli."</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Nav atpazīts"</string>
@@ -93,6 +90,5 @@
<string name="clock_title_default" msgid="6342735240617459864">"Noklusējums"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Burbuļi"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Analogais"</string>
- <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
- <skip />
+ <string name="keyguard_unlock_to_continue" msgid="7509503484250597743">"Lai turpinātu, atbloķējiet ierīci"</string>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-ml/strings.xml b/packages/SystemUI/res-keyguard/values-ml/strings.xml
index e62b435..7919773 100644
--- a/packages/SystemUI/res-keyguard/values-ml/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ml/strings.xml
@@ -78,12 +78,9 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"ഉപകരണം റീസ്റ്റാർട്ടായശേഷം പാറ്റേൺ വരയ്ക്കേണ്ടതുണ്ട്"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"ഉപകരണം റീസ്റ്റാർട്ടായശേഷം പിൻ നൽകേണ്ടതുണ്ട്"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"ഉപകരണം റീസ്റ്റാർട്ടായശേഷം പാസ്വേഡ് നൽകേണ്ടതുണ്ട്"</string>
- <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
- <skip />
+ <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"അധിക സുരക്ഷയ്ക്കായി, പകരം പാറ്റേൺ ഉപയോഗിക്കുക"</string>
+ <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"അധിക സുരക്ഷയ്ക്കായി, പകരം പിൻ ഉപയോഗിക്കുക"</string>
+ <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"അധിക സുരക്ഷയ്ക്കായി, പകരം പാസ്വേഡ് ഉപയോഗിക്കുക"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"ഉപകരണം അഡ്മിൻ ലോക്കുചെയ്തു"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"ഉപകരണം നേരിട്ട് ലോക്കുചെയ്തു"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"തിരിച്ചറിയുന്നില്ല"</string>
@@ -93,6 +90,5 @@
<string name="clock_title_default" msgid="6342735240617459864">"ഡിഫോൾട്ട്"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"ബബിൾ"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"അനലോഗ്"</string>
- <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
- <skip />
+ <string name="keyguard_unlock_to_continue" msgid="7509503484250597743">"തുടരാൻ നിങ്ങളുടെ ഉപകരണം അൺലോക്ക് ചെയ്യുക"</string>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-mr/strings.xml b/packages/SystemUI/res-keyguard/values-mr/strings.xml
index 1454b20..580b547a 100644
--- a/packages/SystemUI/res-keyguard/values-mr/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-mr/strings.xml
@@ -78,12 +78,9 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"डिव्हाइस रीस्टार्ट झाल्यावर पॅटर्न आवश्यक आहे"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"डिव्हाइस रीस्टार्ट झाल्यावर पिन आवश्यक आहे"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"डिव्हाइस रीस्टार्ट झाल्यावर पासवर्ड आवश्यक आहे"</string>
- <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
- <skip />
+ <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"अतिरिक्त सुरक्षेसाठी, त्याऐवजी पॅटर्न वापरा"</string>
+ <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"अतिरिक्त सुरक्षेसाठी, त्याऐवजी पिन वापरा"</string>
+ <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"अतिरिक्त सुरक्षेसाठी, त्याऐवजी पासवर्ड वापरा"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"प्रशासकाद्वारे लॉक केलेले डिव्हाइस"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"डिव्हाइस मॅन्युअली लॉक केले होते"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"ओळखले नाही"</string>
@@ -93,6 +90,5 @@
<string name="clock_title_default" msgid="6342735240617459864">"डीफॉल्ट"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"बबल"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"अॅनालॉग"</string>
- <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
- <skip />
+ <string name="keyguard_unlock_to_continue" msgid="7509503484250597743">"पुढे सुरू ठेवण्यासाठी तुमचे डिव्हाइस अनलॉक करा"</string>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-ms/strings.xml b/packages/SystemUI/res-keyguard/values-ms/strings.xml
index a6d1af9..c179dcb 100644
--- a/packages/SystemUI/res-keyguard/values-ms/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ms/strings.xml
@@ -78,12 +78,9 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Corak diperlukan setelah peranti dimulakan semula"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"PIN diperlukan setelah peranti dimulakan semula"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Kata laluan diperlukan setelah peranti dimulakan semula"</string>
- <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
- <skip />
+ <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Untuk keselamatan tambahan, gunakan corak"</string>
+ <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Untuk keselamatan tambahan, gunakan PIN"</string>
+ <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Untuk keselamatan tambahan, gunakan kata laluan"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Peranti dikunci oleh pentadbir"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Peranti telah dikunci secara manual"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Tidak dikenali"</string>
@@ -93,6 +90,5 @@
<string name="clock_title_default" msgid="6342735240617459864">"Lalai"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Gelembung"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Analog"</string>
- <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
- <skip />
+ <string name="keyguard_unlock_to_continue" msgid="7509503484250597743">"Buka kunci peranti anda untuk meneruskan"</string>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-my/strings.xml b/packages/SystemUI/res-keyguard/values-my/strings.xml
index 5617a11..7c69bdd 100644
--- a/packages/SystemUI/res-keyguard/values-my/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-my/strings.xml
@@ -78,12 +78,9 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"စက်ပစ္စည်းကို ပိတ်ပြီးပြန်ဖွင့်လိုက်သည့်အခါတွင် ပုံစံ လိုအပ်ပါသည်"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"စက်ပစ္စည်းကို ပိတ်ပြီးပြန်ဖွင့်လိုက်သည့်အခါတွင် ပင်နံပါတ် လိုအပ်ပါသည်"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"စက်ပစ္စည်းကို ပိတ်ပြီးပြန်ဖွင့်လိုက်သည့်အခါတွင် စကားဝှက် လိုအပ်ပါသည်"</string>
- <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
- <skip />
+ <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"ထပ်ဆောင်းလုံခြုံရေးအတွက် ၎င်းအစား ပုံစံသုံးပါ"</string>
+ <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"ထပ်ဆောင်းလုံခြုံရေးအတွက် ၎င်းအစား ပင်နံပါတ်သုံးပါ"</string>
+ <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"ထပ်ဆောင်းလုံခြုံရေးအတွက် ၎င်းအစား စကားဝှက်သုံးပါ"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"စက်ပစ္စည်းကို စီမံခန့်ခွဲသူက လော့ခ်ချထားပါသည်"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"စက်ပစ္စည်းကို ကိုယ်တိုင်ကိုယ်ကျ လော့ခ်ချထားခဲ့သည်"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"မသိ"</string>
@@ -93,6 +90,5 @@
<string name="clock_title_default" msgid="6342735240617459864">"မူလ"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"ပူဖောင်းကွက်"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"ရိုးရိုး"</string>
- <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
- <skip />
+ <string name="keyguard_unlock_to_continue" msgid="7509503484250597743">"ရှေ့ဆက်ရန် သင့်စက်ကိုဖွင့်ပါ"</string>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-nb/strings.xml b/packages/SystemUI/res-keyguard/values-nb/strings.xml
index 0ad9e95..e394d1f 100644
--- a/packages/SystemUI/res-keyguard/values-nb/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-nb/strings.xml
@@ -78,12 +78,9 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Du må tegne mønsteret etter at enheten har startet på nytt"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Du må skrive inn PIN-koden etter at enheten har startet på nytt"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Du må skrive inn passordet etter at enheten har startet på nytt"</string>
- <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
- <skip />
+ <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Bruk mønster i stedet, for å øke sikkerheten"</string>
+ <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Bruk PIN-kode i stedet, for å øke sikkerheten"</string>
+ <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Bruk passord i stedet, for å øke sikkerheten"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Enheten er låst av administratoren"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Enheten ble låst manuelt"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Ikke gjenkjent"</string>
@@ -93,6 +90,5 @@
<string name="clock_title_default" msgid="6342735240617459864">"Standard"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Boble"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Analog"</string>
- <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
- <skip />
+ <string name="keyguard_unlock_to_continue" msgid="7509503484250597743">"Lås opp enheten for å fortsette"</string>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-ne/strings.xml b/packages/SystemUI/res-keyguard/values-ne/strings.xml
index 196b74a..9f329e9 100644
--- a/packages/SystemUI/res-keyguard/values-ne/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ne/strings.xml
@@ -78,12 +78,9 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"यन्त्र पुनः सुरु भएपछि ढाँचा आवश्यक पर्दछ"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"यन्त्र पुनः सुरु भएपछि PIN आवश्यक पर्दछ"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"यन्त्र पुनः सुरु भएपछि पासवर्ड आवश्यक पर्दछ"</string>
- <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
- <skip />
+ <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"अतिरिक्त सुरक्षाका लागि यो प्रमाणीकरण विधिको साटो प्याटर्न प्रयोग गर्नुहोस्"</string>
+ <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"अतिरिक्त सुरक्षाका लागि यो प्रमाणीकरण विधिको साटो पिन प्रयोग गर्नुहोस्"</string>
+ <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"अतिरिक्त सुरक्षाका लागि यो प्रमाणीकरण विधिको साटो पासवर्ड प्रयोग गर्नुहोस्"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"प्रशासकले यन्त्रलाई लक गर्नुभएको छ"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"यन्त्रलाई म्यानुअल तरिकाले लक गरिएको थियो"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"पहिचान भएन"</string>
@@ -93,6 +90,5 @@
<string name="clock_title_default" msgid="6342735240617459864">"डिफल्ट"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"बबल"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"एनालग"</string>
- <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
- <skip />
+ <string name="keyguard_unlock_to_continue" msgid="7509503484250597743">"आफ्नो डिभाइस अनलक गरी जारी राख्नुहोस्"</string>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-nl/strings.xml b/packages/SystemUI/res-keyguard/values-nl/strings.xml
index 747b3bb..579824a 100644
--- a/packages/SystemUI/res-keyguard/values-nl/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-nl/strings.xml
@@ -78,12 +78,9 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Patroon vereist nadat het apparaat opnieuw is opgestart"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Pincode vereist nadat het apparaat opnieuw is opgestart"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Wachtwoord vereist nadat het apparaat opnieuw is opgestart"</string>
- <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
- <skip />
+ <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Gebruik in plaats daarvan het patroon voor extra beveiliging"</string>
+ <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Gebruik in plaats daarvan de pincode voor extra beveiliging"</string>
+ <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Gebruik in plaats daarvan het wachtwoord voor extra beveiliging"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Apparaat vergrendeld door beheerder"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Apparaat is handmatig vergrendeld"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Niet herkend"</string>
@@ -93,6 +90,5 @@
<string name="clock_title_default" msgid="6342735240617459864">"Standaard"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Bel"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Analoog"</string>
- <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
- <skip />
+ <string name="keyguard_unlock_to_continue" msgid="7509503484250597743">"Ontgrendel je apparaat om door te gaan"</string>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-pa/strings.xml b/packages/SystemUI/res-keyguard/values-pa/strings.xml
index bf1a359a..5c3fff7 100644
--- a/packages/SystemUI/res-keyguard/values-pa/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-pa/strings.xml
@@ -78,12 +78,9 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"ਡੀਵਾਈਸ ਦੇ ਮੁੜ-ਚਾਲੂ ਹੋਣ \'ਤੇ ਪੈਟਰਨ ਦੀ ਲੋੜ ਹੈ"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"ਡੀਵਾਈਸ ਦੇ ਮੁੜ-ਚਾਲੂ ਹੋਣ \'ਤੇ ਪਿੰਨ ਦੀ ਲੋੜ ਹੈ"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"ਡੀਵਾਈਸ ਦੇ ਮੁੜ-ਚਾਲੂ ਹੋਣ \'ਤੇ ਪਾਸਵਰਡ ਦੀ ਲੋੜ ਹੈ"</string>
- <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
- <skip />
+ <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"ਵਧੀਕ ਸੁਰੱਖਿਆ ਲਈ, ਇਸਦੀ ਬਜਾਏ ਪੈਟਰਨ ਵਰਤੋ"</string>
+ <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"ਵਧੀਕ ਸੁਰੱਖਿਆ ਲਈ, ਇਸਦੀ ਬਜਾਏ ਪਿੰਨ ਵਰਤੋ"</string>
+ <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"ਵਧੀਕ ਸੁਰੱਖਿਆ ਲਈ, ਇਸਦੀ ਬਜਾਏ ਪਾਸਵਰਡ ਵਰਤੋ"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"ਪ੍ਰਸ਼ਾਸਕ ਵੱਲੋਂ ਡੀਵਾਈਸ ਨੂੰ ਲਾਕ ਕੀਤਾ ਗਿਆ"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"ਡੀਵਾਈਸ ਨੂੰ ਹੱਥੀਂ ਲਾਕ ਕੀਤਾ ਗਿਆ"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"ਪਛਾਣ ਨਹੀਂ ਹੋਈ"</string>
@@ -93,6 +90,5 @@
<string name="clock_title_default" msgid="6342735240617459864">"ਪੂਰਵ-ਨਿਰਧਾਰਿਤ"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"ਬੁਲਬੁਲਾ"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"ਐਨਾਲੌਗ"</string>
- <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
- <skip />
+ <string name="keyguard_unlock_to_continue" msgid="7509503484250597743">"ਜਾਰੀ ਰੱਖਣ ਲਈ ਆਪਣੇ ਡੀਵਾਈਸ ਨੂੰ ਅਣਲਾਕ ਕਰੋ"</string>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-pl/strings.xml b/packages/SystemUI/res-keyguard/values-pl/strings.xml
index c49149b..3736386 100644
--- a/packages/SystemUI/res-keyguard/values-pl/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-pl/strings.xml
@@ -78,12 +78,9 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Po ponownym uruchomieniu urządzenia wymagany jest wzór"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Po ponownym uruchomieniu urządzenia wymagany jest kod PIN"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Po ponownym uruchomieniu urządzenia wymagane jest hasło"</string>
- <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
- <skip />
+ <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Ze względów bezpieczeństwa użyj wzoru"</string>
+ <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Ze względów bezpieczeństwa użyj kodu PIN"</string>
+ <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Ze względów bezpieczeństwa użyj hasła"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Urządzenie zablokowane przez administratora"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Urządzenie zostało zablokowane ręcznie"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Nie rozpoznano"</string>
@@ -93,6 +90,5 @@
<string name="clock_title_default" msgid="6342735240617459864">"Domyślna"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Bąbelkowy"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Analogowy"</string>
- <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
- <skip />
+ <string name="keyguard_unlock_to_continue" msgid="7509503484250597743">"Odblokuj urządzenie, aby kontynuować"</string>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-ro/strings.xml b/packages/SystemUI/res-keyguard/values-ro/strings.xml
index 547224e..67ae0fc 100644
--- a/packages/SystemUI/res-keyguard/values-ro/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ro/strings.xml
@@ -78,12 +78,9 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Modelul este necesar după repornirea dispozitivului"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Codul PIN este necesar după repornirea dispozitivului"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Parola este necesară după repornirea dispozitivului"</string>
- <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
- <skip />
+ <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Pentru mai multă securitate, folosește modelul"</string>
+ <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Pentru mai multă securitate, folosește codul PIN"</string>
+ <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Pentru mai multă securitate, folosește parola"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Dispozitiv blocat de administrator"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Dispozitivul a fost blocat manual"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Nu este recunoscut"</string>
@@ -93,6 +90,5 @@
<string name="clock_title_default" msgid="6342735240617459864">"Prestabilit"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Balon"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Analogic"</string>
- <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
- <skip />
+ <string name="keyguard_unlock_to_continue" msgid="7509503484250597743">"Deblochează dispozitivul pentru a continua"</string>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-si/strings.xml b/packages/SystemUI/res-keyguard/values-si/strings.xml
index e5862c3..82df4cb 100644
--- a/packages/SystemUI/res-keyguard/values-si/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-si/strings.xml
@@ -78,12 +78,9 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"උපාංගය නැවත ආරම්භ වූ පසු රටාව අවශ්යයි"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"උපාංගය නැවත ආරම්භ වූ පසු PIN අංකය අවශ්යයි"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"උපාංගය නැවත ආරම්භ වූ පසු මුරපදය අවශ්යයි"</string>
- <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
- <skip />
+ <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"අතිරේක ආරක්ෂාව සඳහා, ඒ වෙනුවට රටාව භාවිතා කරන්න"</string>
+ <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"අතිරේක ආරක්ෂාව සඳහා, ඒ වෙනුවට PIN භාවිතා කරන්න"</string>
+ <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"අතිරේක ආරක්ෂාව සඳහා, ඒ වෙනුවට මුරපදය භාවිතා කරන්න"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"ඔබගේ පරිපාලක විසින් උපාංගය අගුළු දමා ඇත"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"උපාංගය හස්තීයව අගුලු දමන ලදී"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"හඳුනා නොගන්නා ලදී"</string>
@@ -93,6 +90,5 @@
<string name="clock_title_default" msgid="6342735240617459864">"පෙරනිමි"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"බුබුළ"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"ප්රතිසමය"</string>
- <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
- <skip />
+ <string name="keyguard_unlock_to_continue" msgid="7509503484250597743">"ඉදිරියට යාමට ඔබේ උපාංගය අගුළු හරින්න"</string>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-sk/strings.xml b/packages/SystemUI/res-keyguard/values-sk/strings.xml
index efe4ec8..2d8b3b1 100644
--- a/packages/SystemUI/res-keyguard/values-sk/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sk/strings.xml
@@ -78,12 +78,9 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Po reštartovaní zariadenia musíte zadať bezpečnostný vzor"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Po reštartovaní zariadenia musíte zadať kód PIN"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Po reštartovaní zariadenia musíte zadať heslo"</string>
- <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
- <skip />
+ <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"V rámci zvýšenia zabezpečenia použite radšej vzor"</string>
+ <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"V rámci zvýšenia zabezpečenia použite radšej PIN"</string>
+ <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"V rámci zvýšenia zabezpečenia použite radšej heslo"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Zariadenie zamkol správca"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Zariadenie bolo uzamknuté ručne"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Nerozpoznané"</string>
@@ -93,6 +90,5 @@
<string name="clock_title_default" msgid="6342735240617459864">"Predvolený"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Bublina"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Analógový"</string>
- <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
- <skip />
+ <string name="keyguard_unlock_to_continue" msgid="7509503484250597743">"Ak chcete pokračovať, odomknite zariadenie"</string>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-sl/strings.xml b/packages/SystemUI/res-keyguard/values-sl/strings.xml
index 52726c2..4c4ea06 100644
--- a/packages/SystemUI/res-keyguard/values-sl/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sl/strings.xml
@@ -78,12 +78,9 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Po vnovičnem zagonu naprave je treba vnesti vzorec"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Po vnovičnem zagonu naprave je treba vnesti kodo PIN"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Po vnovičnem zagonu naprave je treba vnesti geslo"</string>
- <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
- <skip />
+ <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Za dodatno varnost raje uporabite vzorec."</string>
+ <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Za dodatno varnost raje uporabite kodo PIN."</string>
+ <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Za dodatno varnost raje uporabite geslo."</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Napravo je zaklenil skrbnik"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Naprava je bila ročno zaklenjena"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Ni prepoznano"</string>
@@ -93,6 +90,5 @@
<string name="clock_title_default" msgid="6342735240617459864">"Privzeto"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Mehurček"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Analogno"</string>
- <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
- <skip />
+ <string name="keyguard_unlock_to_continue" msgid="7509503484250597743">"Za nadaljevanje odklenite napravo"</string>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-sq/strings.xml b/packages/SystemUI/res-keyguard/values-sq/strings.xml
index a0a5594..78e217d 100644
--- a/packages/SystemUI/res-keyguard/values-sq/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sq/strings.xml
@@ -78,12 +78,9 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Kërkohet motivi pas rinisjes së pajisjes"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Kërkohet kodi PIN pas rinisjes së pajisjes"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Kërkohet fjalëkalimi pas rinisjes së pajisjes"</string>
- <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
- <skip />
+ <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Për më shumë siguri, përdor motivin më mirë"</string>
+ <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Për më shumë siguri, përdor kodin PIN më mirë"</string>
+ <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Për më shumë siguri, përdor fjalëkalimin më mirë"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Pajisja është e kyçur nga administratori"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Pajisja është kyçur manualisht"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Nuk njihet"</string>
@@ -93,6 +90,5 @@
<string name="clock_title_default" msgid="6342735240617459864">"E parazgjedhur"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Flluskë"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Analoge"</string>
- <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
- <skip />
+ <string name="keyguard_unlock_to_continue" msgid="7509503484250597743">"Shkyç pajisjen tënde për të vazhduar"</string>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-sr/strings.xml b/packages/SystemUI/res-keyguard/values-sr/strings.xml
index e634fdcb5..80d8755 100644
--- a/packages/SystemUI/res-keyguard/values-sr/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sr/strings.xml
@@ -78,12 +78,9 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Треба да унесете шаблон када се уређај поново покрене"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Треба да унесете PIN када се уређај поново покрене"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Треба да унесете лозинку када се уређај поново покрене"</string>
- <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
- <skip />
+ <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"За додатну безбедност користите шаблон"</string>
+ <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"За додатну безбедност користите PIN"</string>
+ <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"За додатну безбедност користите лозинку"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Администратор је закључао уређај"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Уређај је ручно закључан"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Није препознат"</string>
@@ -93,6 +90,5 @@
<string name="clock_title_default" msgid="6342735240617459864">"Подразумевани"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Мехурићи"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Аналогни"</string>
- <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
- <skip />
+ <string name="keyguard_unlock_to_continue" msgid="7509503484250597743">"Откључајте уређај да бисте наставили"</string>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-sv/strings.xml b/packages/SystemUI/res-keyguard/values-sv/strings.xml
index fc9beb1..b5548b9 100644
--- a/packages/SystemUI/res-keyguard/values-sv/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sv/strings.xml
@@ -78,12 +78,9 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Du måste rita mönster när du har startat om enheten"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Du måste ange pinkod när du har startat om enheten"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Du måste ange lösenord när du har startat om enheten"</string>
- <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
- <skip />
+ <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"För ytterligare säkerhet använder du mönstret i stället"</string>
+ <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"För ytterligare säkerhet använder du pinkoden i stället"</string>
+ <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"För ytterligare säkerhet använder du lösenordet i stället"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Administratören har låst enheten"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Enheten har låsts manuellt"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Identifierades inte"</string>
@@ -93,6 +90,5 @@
<string name="clock_title_default" msgid="6342735240617459864">"Standard"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Bubbla"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Analog"</string>
- <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
- <skip />
+ <string name="keyguard_unlock_to_continue" msgid="7509503484250597743">"Lås upp enheten för att fortsätta"</string>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-sw/strings.xml b/packages/SystemUI/res-keyguard/values-sw/strings.xml
index bcab24b..02af18e 100644
--- a/packages/SystemUI/res-keyguard/values-sw/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sw/strings.xml
@@ -78,12 +78,9 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Unafaa kuchora mchoro baada ya kuwasha kifaa upya"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Unafaa kuweka PIN baada ya kuwasha kifaa upya"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Unafaa kuweka nenosiri baada ya kuwasha kifaa upya"</string>
- <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
- <skip />
+ <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Kwa usalama wa ziada, tumia mchoro badala yake"</string>
+ <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Kwa usalama wa ziada, tumia PIN badala yake"</string>
+ <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Kwa usalama wa ziada, tumia nenosiri badala yake"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Msimamizi amefunga kifaa"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Umefunga kifaa mwenyewe"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Haitambuliwi"</string>
@@ -93,6 +90,5 @@
<string name="clock_title_default" msgid="6342735240617459864">"Chaguomsingi"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Kiputo"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Analogi"</string>
- <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
- <skip />
+ <string name="keyguard_unlock_to_continue" msgid="7509503484250597743">"Fungua kifaa chako ili uendelee"</string>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-ta/strings.xml b/packages/SystemUI/res-keyguard/values-ta/strings.xml
index 88d5760..0d32d46 100644
--- a/packages/SystemUI/res-keyguard/values-ta/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ta/strings.xml
@@ -78,12 +78,9 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"சாதனத்தை மீண்டும் தொடங்கியதும், பேட்டர்னை வரைய வேண்டும்"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"சாதனத்தை மீண்டும் தொடங்கியதும், பின்னை உள்ளிட வேண்டும்"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"சாதனத்தை மீண்டும் தொடங்கியதும், கடவுச்சொல்லை உள்ளிட வேண்டும்"</string>
- <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
- <skip />
+ <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"கூடுதல் பாதுகாப்பிற்குப் பேட்டர்னைப் பயன்படுத்தவும்"</string>
+ <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"கூடுதல் பாதுகாப்பிற்குப் பின்னை (PIN) பயன்படுத்தவும்"</string>
+ <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"கூடுதல் பாதுகாப்பிற்குக் கடவுச்சொல்லைப் பயன்படுத்தவும்"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"நிர்வாகி சாதனத்தைப் பூட்டியுள்ளார்"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"பயனர் சாதனத்தைப் பூட்டியுள்ளார்"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"அடையாளங்காணபடவில்லை"</string>
@@ -93,6 +90,5 @@
<string name="clock_title_default" msgid="6342735240617459864">"இயல்பு"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"பபிள்"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"அனலாக்"</string>
- <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
- <skip />
+ <string name="keyguard_unlock_to_continue" msgid="7509503484250597743">"தொடர, சாதனத்தை அன்லாக் செய்யுங்கள்"</string>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-te/strings.xml b/packages/SystemUI/res-keyguard/values-te/strings.xml
index 3a0111a..f519daf 100644
--- a/packages/SystemUI/res-keyguard/values-te/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-te/strings.xml
@@ -78,12 +78,9 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"పరికరాన్ని పునఃప్రారంభించిన తర్వాత నమూనాను గీయాలి"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"డివైజ్ను పునఃప్రారంభించిన తర్వాత పిన్ నమోదు చేయాలి"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"పరికరాన్ని పునఃప్రారంభించిన తర్వాత పాస్వర్డ్ను నమోదు చేయాలి"</string>
- <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
- <skip />
+ <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"అదనపు సెక్యూరిటీ కోసం, బదులుగా ఆకృతిని ఉపయోగించండి"</string>
+ <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"అదనపు సెక్యూరిటీ కోసం, బదులుగా PINను ఉపయోగించండి"</string>
+ <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"అదనపు సెక్యూరిటీ కోసం, బదులుగా పాస్వర్డ్ను ఉపయోగించండి"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"పరికరం నిర్వాహకుల ద్వారా లాక్ చేయబడింది"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"పరికరం మాన్యువల్గా లాక్ చేయబడింది"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"గుర్తించలేదు"</string>
@@ -93,6 +90,5 @@
<string name="clock_title_default" msgid="6342735240617459864">"ఆటోమేటిక్"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"బబుల్"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"ఎనలాగ్"</string>
- <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
- <skip />
+ <string name="keyguard_unlock_to_continue" msgid="7509503484250597743">"కొనసాగించడానికి మీ పరికరాన్ని అన్లాక్ చేయండి"</string>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-tr/strings.xml b/packages/SystemUI/res-keyguard/values-tr/strings.xml
index e520762..80dae8c 100644
--- a/packages/SystemUI/res-keyguard/values-tr/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-tr/strings.xml
@@ -78,12 +78,9 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Cihaz yeniden başladıktan sonra desen gerekir"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Cihaz yeniden başladıktan sonra PIN gerekir"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Cihaz yeniden başladıktan sonra şifre gerekir"</string>
- <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
- <skip />
+ <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Ek güvenlik için bunun yerine desen kullanın"</string>
+ <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Ek güvenlik için bunun yerine PIN kullanın"</string>
+ <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Ek güvenlik için bunun yerine şifre kullanın"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Cihaz, yönetici tarafından kilitlendi"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Cihazın manuel olarak kilitlendi"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Tanınmadı"</string>
@@ -93,6 +90,5 @@
<string name="clock_title_default" msgid="6342735240617459864">"Varsayılan"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Baloncuk"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Analog"</string>
- <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
- <skip />
+ <string name="keyguard_unlock_to_continue" msgid="7509503484250597743">"Devam etmek için cihazınızın kilidini açın"</string>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-uk/strings.xml b/packages/SystemUI/res-keyguard/values-uk/strings.xml
index 613181d..ff594ae 100644
--- a/packages/SystemUI/res-keyguard/values-uk/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-uk/strings.xml
@@ -78,12 +78,9 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Після перезавантаження пристрою потрібно ввести ключ"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Після перезавантаження пристрою потрібно ввести PIN-код"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Після перезавантаження пристрою потрібно ввести пароль"</string>
- <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
- <skip />
+ <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"З міркувань додаткової безпеки скористайтеся ключем"</string>
+ <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"З міркувань додаткової безпеки скористайтеся PIN-кодом"</string>
+ <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"З міркувань додаткової безпеки скористайтеся паролем"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Адміністратор заблокував пристрій"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Пристрій заблоковано вручну"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Не розпізнано"</string>
@@ -93,6 +90,5 @@
<string name="clock_title_default" msgid="6342735240617459864">"За умовчанням"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Бульбашковий"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Аналоговий"</string>
- <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
- <skip />
+ <string name="keyguard_unlock_to_continue" msgid="7509503484250597743">"Розблокуйте пристрій, щоб продовжити"</string>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-ur/strings.xml b/packages/SystemUI/res-keyguard/values-ur/strings.xml
index a122f85..9308260 100644
--- a/packages/SystemUI/res-keyguard/values-ur/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ur/strings.xml
@@ -78,12 +78,9 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"آلہ دوبارہ چالو ہونے کے بعد پیٹرن درکار ہوتا ہے"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"آلہ دوبارہ چالو ہونے کے بعد PIN درکار ہوتا ہے"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"آلہ دوبارہ چالو ہونے کے بعد پاس ورڈ درکار ہوتا ہے"</string>
- <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
- <skip />
+ <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"اضافی سیکیورٹی کے لئے، اس کے بجائے پیٹرن استعمال کریں"</string>
+ <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"اضافی سیکیورٹی کے لئے، اس کے بجائے PIN استعمال کریں"</string>
+ <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"اضافی سیکیورٹی کے لئے، اس کے بجائے پاس ورڈ استعمال کریں"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"آلہ منتظم کی جانب سے مقفل ہے"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"آلہ کو دستی طور پر مقفل کیا گیا تھا"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"تسلیم شدہ نہیں ہے"</string>
@@ -93,6 +90,5 @@
<string name="clock_title_default" msgid="6342735240617459864">"ڈیفالٹ"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"بلبلہ"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"اینالاگ"</string>
- <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
- <skip />
+ <string name="keyguard_unlock_to_continue" msgid="7509503484250597743">"جاری رکھنے کے لئے اپنا آلہ غیر مقفل کریں"</string>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-vi/strings.xml b/packages/SystemUI/res-keyguard/values-vi/strings.xml
index e7c9295..2771ada 100644
--- a/packages/SystemUI/res-keyguard/values-vi/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-vi/strings.xml
@@ -78,12 +78,9 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Yêu cầu hình mở khóa sau khi thiết bị khởi động lại"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Yêu cầu mã PIN sau khi thiết bị khởi động lại"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Yêu cầu mật khẩu sau khi thiết bị khởi động lại"</string>
- <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
- <skip />
+ <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Để tăng cường bảo mật, hãy sử dụng hình mở khoá"</string>
+ <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Để tăng cường bảo mật, hãy sử dụng mã PIN"</string>
+ <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Để tăng cường bảo mật, hãy sử dụng mật khẩu"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Thiết bị đã bị quản trị viên khóa"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Thiết bị đã bị khóa theo cách thủ công"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Không nhận dạng được"</string>
@@ -93,6 +90,5 @@
<string name="clock_title_default" msgid="6342735240617459864">"Mặc định"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Bong bóng"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"Đồng hồ kim"</string>
- <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
- <skip />
+ <string name="keyguard_unlock_to_continue" msgid="7509503484250597743">"Mở khoá thiết bị của bạn để tiếp tục"</string>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml b/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml
index d37d645..fb92838 100644
--- a/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml
@@ -78,12 +78,9 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"重启设备后需要绘制解锁图案"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"重启设备后需要输入 PIN 码"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"重启设备后需要输入密码"</string>
- <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
- <skip />
+ <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"为增强安全性,请改用图案"</string>
+ <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"为增强安全性,请改用 PIN 码"</string>
+ <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"为增强安全性,请改用密码"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"管理员已锁定设备"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"此设备已手动锁定"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"无法识别"</string>
@@ -93,6 +90,5 @@
<string name="clock_title_default" msgid="6342735240617459864">"默认"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"泡泡"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"指针"</string>
- <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
- <skip />
+ <string name="keyguard_unlock_to_continue" msgid="7509503484250597743">"解锁设备才能继续操作"</string>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-zh-rHK/strings.xml b/packages/SystemUI/res-keyguard/values-zh-rHK/strings.xml
index 9dbb8f2..49050e5 100644
--- a/packages/SystemUI/res-keyguard/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-zh-rHK/strings.xml
@@ -78,12 +78,9 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"裝置重新啟動後,必須畫出上鎖圖案才能使用"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"裝置重新啟動後,必須輸入 PIN 碼才能使用"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"裝置重新啟動後,必須輸入密碼才能使用"</string>
- <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
- <skip />
+ <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"為提升安全性,請改用圖案"</string>
+ <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"為提升安全性,請改用 PIN"</string>
+ <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"為提升安全性,請改用密碼"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"裝置已由管理員鎖定"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"使用者已手動將裝置上鎖"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"未能識別"</string>
@@ -93,6 +90,5 @@
<string name="clock_title_default" msgid="6342735240617459864">"預設"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"泡泡"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"指針"</string>
- <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
- <skip />
+ <string name="keyguard_unlock_to_continue" msgid="7509503484250597743">"解鎖裝置以繼續"</string>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml b/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml
index ebb88e1..e5a363c 100644
--- a/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml
@@ -78,12 +78,9 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"裝置重新啟動後需要畫出解鎖圖案"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"裝置重新啟動後需要輸入 PIN 碼"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"裝置重新啟動後需要輸入密碼"</string>
- <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
- <skip />
+ <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"為強化安全性,請改用解鎖圖案"</string>
+ <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"為強化安全性,請改用 PIN 碼"</string>
+ <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"為強化安全性,請改用密碼"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"管理員已鎖定裝置"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"裝置已手動鎖定"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"無法識別"</string>
@@ -93,6 +90,5 @@
<string name="clock_title_default" msgid="6342735240617459864">"預設"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"泡泡"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"類比"</string>
- <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
- <skip />
+ <string name="keyguard_unlock_to_continue" msgid="7509503484250597743">"解鎖裝置才能繼續操作"</string>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-zu/strings.xml b/packages/SystemUI/res-keyguard/values-zu/strings.xml
index 57e56f7..72ca6c0 100644
--- a/packages/SystemUI/res-keyguard/values-zu/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-zu/strings.xml
@@ -78,12 +78,9 @@
<string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Iphethini iyadingeka ngemuva kokuqala kabusha kwedivayisi"</string>
<string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Iphinikhodi iyadingeka ngemuva kokuqala kabusha kwedivayisi"</string>
<string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Iphasiwedi iyadingeka ngemuva kokuqala kabusha kwedivayisi"</string>
- <!-- no translation found for kg_prompt_reason_timeout_pattern (5514969660010197363) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_pin (4227962059353859376) -->
- <skip />
- <!-- no translation found for kg_prompt_reason_timeout_password (8810879144143933690) -->
- <skip />
+ <string name="kg_prompt_reason_timeout_pattern" msgid="5514969660010197363">"Ukuze uthole ukuvikeleka okwengeziwe, sebenzisa iphetheni esikhundleni salokho"</string>
+ <string name="kg_prompt_reason_timeout_pin" msgid="4227962059353859376">"Ukuze uthole ukuvikeleka okwengeziwe, sebenzisa i-PIN esikhundleni salokho"</string>
+ <string name="kg_prompt_reason_timeout_password" msgid="8810879144143933690">"Ukuze uthole ukuvikeleka okwengeziwe, sebenzisa iphasiwedi esikhundleni salokho"</string>
<string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Idivayisi ikhiywe ngumlawuli"</string>
<string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Idivayisi ikhiywe ngokwenza"</string>
<string name="kg_face_not_recognized" msgid="7903950626744419160">"Akwaziwa"</string>
@@ -93,6 +90,5 @@
<string name="clock_title_default" msgid="6342735240617459864">"Okuzenzekelayo"</string>
<string name="clock_title_bubble" msgid="2204559396790593213">"Ibhamuza"</string>
<string name="clock_title_analog" msgid="8409262532900918273">"I-Analog"</string>
- <!-- no translation found for keyguard_unlock_to_continue (7509503484250597743) -->
- <skip />
+ <string name="keyguard_unlock_to_continue" msgid="7509503484250597743">"Vula idivayisi yakho ukuze uqhubeke"</string>
</resources>
diff --git a/packages/SystemUI/res/layout/media_session_view.xml b/packages/SystemUI/res/layout/media_session_view.xml
index c526d9c..9b8b611 100644
--- a/packages/SystemUI/res/layout/media_session_view.xml
+++ b/packages/SystemUI/res/layout/media_session_view.xml
@@ -44,6 +44,15 @@
android:background="@drawable/qs_media_outline_album_bg"
/>
+ <com.android.systemui.ripple.MultiRippleView
+ android:id="@+id/touch_ripple_view"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/qs_media_session_height_expanded"
+ app:layout_constraintStart_toStartOf="@id/album_art"
+ app:layout_constraintEnd_toEndOf="@id/album_art"
+ app:layout_constraintTop_toTopOf="@id/album_art"
+ app:layout_constraintBottom_toBottomOf="@id/album_art" />
+
<!-- Guideline for output switcher -->
<androidx.constraintlayout.widget.Guideline
android:id="@+id/center_vertical_guideline"
diff --git a/packages/SystemUI/res/layout/user_switcher_fullscreen.xml b/packages/SystemUI/res/layout/user_switcher_fullscreen.xml
index c2c79cb..78884ff 100644
--- a/packages/SystemUI/res/layout/user_switcher_fullscreen.xml
+++ b/packages/SystemUI/res/layout/user_switcher_fullscreen.xml
@@ -14,58 +14,84 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<com.android.systemui.user.UserSwitcherRootView
+<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
android:id="@+id/user_switcher_root"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:layout_marginVertical="40dp"
- android:layout_marginHorizontal="60dp">
+ android:orientation="vertical">
- <androidx.constraintlayout.helper.widget.Flow
- android:id="@+id/flow"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintTop_toTopOf="parent"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintEnd_toEndOf="parent"
- app:flow_horizontalBias="0.5"
- app:flow_verticalAlign="center"
- app:flow_wrapMode="chain"
- app:flow_horizontalGap="@dimen/user_switcher_fullscreen_horizontal_gap"
- app:flow_verticalGap="44dp"
- app:flow_horizontalStyle="packed"/>
+ <ScrollView
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1"
+ android:fillViewport="true">
- <TextView
- android:id="@+id/cancel"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:gravity="center"
- app:layout_constraintHeight_min="48dp"
- app:layout_constraintEnd_toStartOf="@+id/add"
- app:layout_constraintBottom_toBottomOf="parent"
- android:paddingHorizontal="@dimen/user_switcher_fullscreen_button_padding"
- android:textSize="@dimen/user_switcher_fullscreen_button_text_size"
- android:textColor="?androidprv:attr/colorAccentPrimary"
- android:text="@string/cancel" />
+ <com.android.systemui.user.UserSwitcherRootView
+ android:id="@+id/user_switcher_grid_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingTop="40dp"
+ android:paddingHorizontal="60dp">
- <TextView
- android:id="@+id/add"
- style="@style/Widget.Dialog.Button.BorderButton"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:gravity="center"
- android:paddingHorizontal="@dimen/user_switcher_fullscreen_button_padding"
- android:text="@string/add"
- android:textColor="?androidprv:attr/colorAccentPrimary"
- android:textSize="@dimen/user_switcher_fullscreen_button_text_size"
- android:visibility="gone"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintHeight_min="48dp" />
-</com.android.systemui.user.UserSwitcherRootView>
+ <androidx.constraintlayout.helper.widget.Flow
+ android:id="@+id/flow"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:flow_horizontalBias="0.5"
+ app:flow_verticalAlign="center"
+ app:flow_wrapMode="chain"
+ app:flow_horizontalGap="@dimen/user_switcher_fullscreen_horizontal_gap"
+ app:flow_verticalGap="44dp"
+ app:flow_horizontalStyle="packed"/>
+ </com.android.systemui.user.UserSwitcherRootView>
+
+ </ScrollView>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="96dp"
+ android:orientation="horizontal"
+ android:gravity="center_vertical|end"
+ android:paddingEnd="48dp">
+
+ <TextView
+ android:id="@+id/cancel"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:gravity="center"
+ android:minHeight="48dp"
+ android:paddingHorizontal="@dimen/user_switcher_fullscreen_button_padding"
+ android:textSize="@dimen/user_switcher_fullscreen_button_text_size"
+ android:textColor="?androidprv:attr/colorAccentPrimary"
+ android:text="@string/cancel" />
+
+ <Space
+ android:layout_width="24dp"
+ android:layout_height="0dp"
+ />
+
+ <TextView
+ android:id="@+id/add"
+ style="@style/Widget.Dialog.Button.BorderButton"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:gravity="center"
+ android:paddingHorizontal="@dimen/user_switcher_fullscreen_button_padding"
+ android:text="@string/add"
+ android:textColor="?androidprv:attr/colorAccentPrimary"
+ android:textSize="@dimen/user_switcher_fullscreen_button_text_size"
+ android:visibility="gone"
+ android:minHeight="48dp" />
+
+ </LinearLayout>
+
+</LinearLayout>
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 3dc85d70..2f2780b 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -248,7 +248,8 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Helderheid"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Kleuromkering"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Kleurregstelling"</string>
- <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Gebruikerinstellings"</string>
+ <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) -->
+ <skip />
<string name="quick_settings_done" msgid="2163641301648855793">"Klaar"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Maak toe"</string>
<string name="quick_settings_connected" msgid="3873605509184830379">"Gekoppel"</string>
@@ -727,6 +728,14 @@
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Skakel mobiele data af?"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"Jy sal nie deur <xliff:g id="CARRIER">%s</xliff:g> toegang tot data of die internet hê nie. Internet sal net deur Wi-Fi beskikbaar wees."</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"jou diensverskaffer"</string>
+ <!-- no translation found for auto_data_switch_disable_title (5146527155665190652) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_disable_message (5885533647399535852) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_negative_button (2370876875999891444) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_positive_button (8531782041263087564) -->
+ <skip />
<string name="touch_filtered_warning" msgid="8119511393338714836">"Instellings kan nie jou antwoord verifieer nie omdat \'n program \'n toestemmingversoek verberg."</string>
<string name="slice_permission_title" msgid="3262615140094151017">"Laat <xliff:g id="APP_0">%1$s</xliff:g> toe om <xliff:g id="APP_2">%2$s</xliff:g>-skyfies te wys?"</string>
<string name="slice_permission_text_1" msgid="6675965177075443714">"– Dit kan inligting van <xliff:g id="APP">%1$s</xliff:g> af lees"</string>
@@ -785,12 +794,18 @@
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Vergrootglasvensterinstellings"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Tik om toeganklikheidkenmerke oop te maak Pasmaak of vervang knoppie in Instellings.\n\n"<annotation id="link">"Bekyk instellings"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Skuif knoppie na kant om dit tydelik te versteek"</string>
+ <!-- no translation found for accessibility_floating_button_undo (511112888715708241) -->
+ <skip />
+ <!-- no translation found for accessibility_floating_button_undo_message_text (3044079592757099698) -->
+ <skip />
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Beweeg na links bo"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Beweeg na regs bo"</string>
<string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Beweeg na links onder"</string>
<string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Beweeg na regs onder"</string>
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Beweeg na rand en versteek"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Beweeg weg van rand en wys"</string>
+ <!-- no translation found for accessibility_floating_button_action_remove_menu (6730432848162552135) -->
+ <skip />
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"wissel"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Toestelkontroles"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Kies program om kontroles by te voeg"</string>
@@ -933,6 +948,10 @@
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobiele data"</string>
<string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Gekoppel"</string>
+ <!-- no translation found for mobile_data_temp_connection_active (4590222725908806824) -->
+ <skip />
+ <!-- no translation found for mobile_data_poor_connection (819617772268371434) -->
+ <skip />
<string name="mobile_data_off_summary" msgid="3663995422004150567">"Mobiele data sal nie outomaties koppel nie"</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"Geen verbinding nie"</string>
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"Geen ander netwerke beskikbaar nie"</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index fb60f9b..3ccb686 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -248,7 +248,8 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"ብሩህነት"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"ተቃራኒ ቀለም"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"የቀለም ማስተካከያ"</string>
- <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"የተጠቃሚ ቅንብሮች"</string>
+ <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) -->
+ <skip />
<string name="quick_settings_done" msgid="2163641301648855793">"ተከናውኗል"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"ዝጋ"</string>
<string name="quick_settings_connected" msgid="3873605509184830379">"ተገናኝቷል"</string>
@@ -727,6 +728,14 @@
<string name="mobile_data_disable_title" msgid="5366476131671617790">"የተንቀሳቃሽ ስልክ ውሂብ ይጥፋ?"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"በ<xliff:g id="CARRIER">%s</xliff:g> በኩል የውሂብ ወይም የበይነመረቡ መዳረሻ አይኖረዎትም። በይነመረብ በWi-Fi በኩል ብቻ ነው የሚገኝ የሚሆነው።"</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"የእርስዎ አገልግሎት አቅራቢ"</string>
+ <!-- no translation found for auto_data_switch_disable_title (5146527155665190652) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_disable_message (5885533647399535852) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_negative_button (2370876875999891444) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_positive_button (8531782041263087564) -->
+ <skip />
<string name="touch_filtered_warning" msgid="8119511393338714836">"አንድ መተግበሪያ የፍቃድ ጥያቄ እያገደ ስለሆነ ቅንብሮች ጥያቄዎን ማረጋገጥ አይችሉም።"</string>
<string name="slice_permission_title" msgid="3262615140094151017">"<xliff:g id="APP_0">%1$s</xliff:g> የ<xliff:g id="APP_2">%2$s</xliff:g> ቁራጮችን እንዲያሳይ ይፈቀድለት?"</string>
<string name="slice_permission_text_1" msgid="6675965177075443714">"- ከ<xliff:g id="APP">%1$s</xliff:g> የመጣ መረጃን ማንበብ ይችላል"</string>
@@ -785,12 +794,18 @@
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"የማጉያ መስኮት ቅንብሮች"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"የተደራሽነት ባህሪያትን ለመክፈት መታ ያድርጉ። ይህንን አዝራር በቅንብሮች ውስጥ ያብጁ ወይም ይተኩ።\n\n"<annotation id="link">"ቅንብሮችን አሳይ"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"ለጊዜው ለመደበቅ አዝራሩን ወደ ጠርዝ ያንቀሳቅሱ"</string>
+ <!-- no translation found for accessibility_floating_button_undo (511112888715708241) -->
+ <skip />
+ <!-- no translation found for accessibility_floating_button_undo_message_text (3044079592757099698) -->
+ <skip />
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"ወደ ላይኛው ግራ አንቀሳቅስ"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"ወደ ላይኛው ቀኝ አንቀሳቅስ"</string>
<string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"የግርጌውን ግራ አንቀሳቅስ"</string>
<string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"ታችኛውን ቀኝ አንቀሳቅስ"</string>
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"ወደ ጠርዝ አንቀሳቅስ እና ደደብቅ"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"ጠርዙን ወደ ውጭ አንቀሳቅስ እና አሳይ"</string>
+ <!-- no translation found for accessibility_floating_button_action_remove_menu (6730432848162552135) -->
+ <skip />
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"ቀያይር"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"የመሣሪያ መቆጣጠሪያዎች"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"መቆጣጠሪያዎችን ለማከል መተግበሪያ ይምረጡ"</string>
@@ -933,6 +948,10 @@
<string name="mobile_data_settings_title" msgid="3955246641380064901">"የተንቀሳቃሽ ስልክ ውሂብ"</string>
<string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"ተገናኝቷል"</string>
+ <!-- no translation found for mobile_data_temp_connection_active (4590222725908806824) -->
+ <skip />
+ <!-- no translation found for mobile_data_poor_connection (819617772268371434) -->
+ <skip />
<string name="mobile_data_off_summary" msgid="3663995422004150567">"የተንቀሳቃሽ ስልክ ውሂብ በራስ-ሰር አይገናኝም"</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"ግንኙነት የለም"</string>
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"ሌላ አውታረ መረብ የሉም"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index f8567c7..c90fb25 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -248,7 +248,8 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"السطوع"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"قلب الألوان"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"تصحيح الألوان"</string>
- <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"إعدادات المستخدم"</string>
+ <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) -->
+ <skip />
<string name="quick_settings_done" msgid="2163641301648855793">"تم"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"إغلاق"</string>
<string name="quick_settings_connected" msgid="3873605509184830379">"متصل"</string>
@@ -727,6 +728,14 @@
<string name="mobile_data_disable_title" msgid="5366476131671617790">"هل تريد إيقاف بيانات الجوّال؟"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"لن تتمكّن من استخدام البيانات أو الإنترنت من خلال <xliff:g id="CARRIER">%s</xliff:g>. ولن يتوفر اتصال الإنترنت إلا عبر Wi-Fi."</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"مشغّل شبكة الجوّال"</string>
+ <!-- no translation found for auto_data_switch_disable_title (5146527155665190652) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_disable_message (5885533647399535852) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_negative_button (2370876875999891444) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_positive_button (8531782041263087564) -->
+ <skip />
<string name="touch_filtered_warning" msgid="8119511393338714836">"لا يمكن للإعدادات التحقق من ردك لأن هناك تطبيقًا يحجب طلب الإذن."</string>
<string name="slice_permission_title" msgid="3262615140094151017">"هل تريد السماح لتطبيق <xliff:g id="APP_0">%1$s</xliff:g> بعرض شرائح <xliff:g id="APP_2">%2$s</xliff:g>؟"</string>
<string name="slice_permission_text_1" msgid="6675965177075443714">"- يستطيع قراءة المعلومات من <xliff:g id="APP">%1$s</xliff:g>"</string>
@@ -785,12 +794,18 @@
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"إعدادات نافذة مكبّر الشاشة"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"انقر لفتح ميزات تسهيل الاستخدام. يمكنك تخصيص هذا الزر أو استبداله من الإعدادات.\n\n"<annotation id="link">"عرض الإعدادات"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"يمكنك نقل الزر إلى الحافة لإخفائه مؤقتًا."</string>
+ <!-- no translation found for accessibility_floating_button_undo (511112888715708241) -->
+ <skip />
+ <!-- no translation found for accessibility_floating_button_undo_message_text (3044079592757099698) -->
+ <skip />
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"نقل إلى أعلى يمين الشاشة"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"نقل إلى أعلى يسار الشاشة"</string>
<string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"نقل إلى أسفل يمين الشاشة"</string>
<string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"نقل إلى أسفل يسار الشاشة"</string>
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"نقله إلى الحافة وإخفاؤه"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"نقله إلى خارج الحافة وإظهاره"</string>
+ <!-- no translation found for accessibility_floating_button_action_remove_menu (6730432848162552135) -->
+ <skip />
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"إيقاف/تفعيل"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"التحكم بالجهاز"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"اختيار تطبيق لإضافة عناصر التحكّم"</string>
@@ -933,6 +948,10 @@
<string name="mobile_data_settings_title" msgid="3955246641380064901">"بيانات الجوّال"</string>
<string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"متصلة بالإنترنت"</string>
+ <!-- no translation found for mobile_data_temp_connection_active (4590222725908806824) -->
+ <skip />
+ <!-- no translation found for mobile_data_poor_connection (819617772268371434) -->
+ <skip />
<string name="mobile_data_off_summary" msgid="3663995422004150567">"لن يتم تلقائيًا الاتصال ببيانات الجوّال."</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"لا يتوفّر اتصال بالإنترنت"</string>
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"لا تتوفّر شبكات أخرى."</string>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index 4fca5f2e..c363eee 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -248,7 +248,8 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"উজ্জ্বলতা"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"ৰং বিপৰীতকৰণ"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"ৰং শুধৰণী"</string>
- <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"ব্যৱহাৰকাৰীৰ ছেটিং"</string>
+ <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) -->
+ <skip />
<string name="quick_settings_done" msgid="2163641301648855793">"সম্পন্ন কৰা হ’ল"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"বন্ধ কৰক"</string>
<string name="quick_settings_connected" msgid="3873605509184830379">"সংযোগ কৰা হ’ল"</string>
@@ -727,6 +728,14 @@
<string name="mobile_data_disable_title" msgid="5366476131671617790">"ম’বাইল ডেটা অফ কৰিবনে?"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"আপুনি <xliff:g id="CARRIER">%s</xliff:g>ৰ জৰিয়তে ডেটা সংযোগ বা ইণ্টাৰনেট সংযোগ নাপাব। কেৱল ৱাই-ফাইৰ যোগেৰে ইণ্টাৰনেট উপলব্ধ হ\'ব।"</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"আপোনাৰ বাহক"</string>
+ <!-- no translation found for auto_data_switch_disable_title (5146527155665190652) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_disable_message (5885533647399535852) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_negative_button (2370876875999891444) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_positive_button (8531782041263087564) -->
+ <skip />
<string name="touch_filtered_warning" msgid="8119511393338714836">"এটা এপে অনুমতি বিচাৰি কৰা অনুৰোধ এটা ঢাকি ধৰা বাবে ছেটিঙৰ পৰা আপোনাৰ উত্তৰ সত্যাপন কৰিব পৰা নাই।"</string>
<string name="slice_permission_title" msgid="3262615140094151017">"<xliff:g id="APP_0">%1$s</xliff:g>ক <xliff:g id="APP_2">%2$s</xliff:g>ৰ অংশ দেখুওৱাবলৈ অনুমতি দিবনে?"</string>
<string name="slice_permission_text_1" msgid="6675965177075443714">"- ই <xliff:g id="APP">%1$s</xliff:g>ৰ তথ্য পঢ়িব পাৰে"</string>
@@ -785,12 +794,18 @@
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"বিবৰ্ধকৰ ৱিণ্ড’ৰ ছেটিং"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"সাধ্য সুবিধাসমূহ খুলিবলৈ টিপক। ছেটিঙত এই বুটামটো কাষ্টমাইজ অথবা সলনি কৰক।\n\n"<annotation id="link">"ছেটিং চাওক"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"বুটামটোক সাময়িকভাৱে লুকুৱাবলৈ ইয়াক একেবাৰে কাষলৈ লৈ যাওক"</string>
+ <!-- no translation found for accessibility_floating_button_undo (511112888715708241) -->
+ <skip />
+ <!-- no translation found for accessibility_floating_button_undo_message_text (3044079592757099698) -->
+ <skip />
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"শীৰ্ষৰ বাওঁফালে নিয়ক"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"শীৰ্ষৰ সোঁফালে নিয়ক"</string>
<string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"তলৰ বাওঁফালে নিয়ক"</string>
<string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"তলৰ সোঁফালে নিয়ক"</string>
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"কাষলৈ নিয়ক আৰু লুকুৱাওক"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"কাষৰ বাহিৰলৈ নিয়ক আৰু দেখুৱাওক"</string>
+ <!-- no translation found for accessibility_floating_button_action_remove_menu (6730432848162552135) -->
+ <skip />
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"ট’গল কৰক"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"ডিভাইচৰ নিয়ন্ত্ৰণসমূহ"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"নিয়ন্ত্ৰণসমূহ যোগ কৰিবলৈ এপ্ বাছনি কৰক"</string>
@@ -933,6 +948,10 @@
<string name="mobile_data_settings_title" msgid="3955246641380064901">"ম’বাইল ডেটা"</string>
<string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"সংযোজিত হৈ আছে"</string>
+ <!-- no translation found for mobile_data_temp_connection_active (4590222725908806824) -->
+ <skip />
+ <!-- no translation found for mobile_data_poor_connection (819617772268371434) -->
+ <skip />
<string name="mobile_data_off_summary" msgid="3663995422004150567">"ম’বাইল ডেটা স্বয়ংক্ৰিয়ভাৱে সংযুক্ত নহ’ব"</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"সংযোগ নাই"</string>
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"অন্য কোনো নেটৱৰ্ক উপলব্ধ নহয়"</string>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index 7fa603f..c5f143b 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -248,7 +248,8 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Parlaqlıq"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Rəng inversiyası"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Rəng korreksiyası"</string>
- <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"İstifadəçi ayarları"</string>
+ <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) -->
+ <skip />
<string name="quick_settings_done" msgid="2163641301648855793">"Hazır"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Bağlayın"</string>
<string name="quick_settings_connected" msgid="3873605509184830379">"Qoşulu"</string>
@@ -727,6 +728,14 @@
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Mobil data söndürülsün?"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"<xliff:g id="CARRIER">%s</xliff:g> ilə data və ya internetə daxil ola bilməyəcəksiniz. İnternet yalnız Wi-Fi ilə əlçatan olacaq."</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"operatorunuz"</string>
+ <!-- no translation found for auto_data_switch_disable_title (5146527155665190652) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_disable_message (5885533647399535852) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_negative_button (2370876875999891444) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_positive_button (8531782041263087564) -->
+ <skip />
<string name="touch_filtered_warning" msgid="8119511393338714836">"Tətbiq icazə sorğusunu gizlətdiyi üçün Ayarlar cavabınızı doğrulaya bilməz."</string>
<string name="slice_permission_title" msgid="3262615140094151017">"<xliff:g id="APP_0">%1$s</xliff:g> tətbiqinə <xliff:g id="APP_2">%2$s</xliff:g> hissələrini göstərmək üçün icazə verilsin?"</string>
<string name="slice_permission_text_1" msgid="6675965177075443714">"- <xliff:g id="APP">%1$s</xliff:g> tətbiqindən məlumat oxuya bilər"</string>
@@ -785,12 +794,18 @@
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Böyüdücü pəncərə ayarları"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Əlçatımlılıq funksiyalarını açmaq üçün toxunun. Ayarlarda bu düyməni fərdiləşdirin və ya dəyişdirin.\n\n"<annotation id="link">"Ayarlara baxın"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Düyməni müvəqqəti gizlətmək üçün kənara çəkin"</string>
+ <!-- no translation found for accessibility_floating_button_undo (511112888715708241) -->
+ <skip />
+ <!-- no translation found for accessibility_floating_button_undo_message_text (3044079592757099698) -->
+ <skip />
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Yuxarıya sola köçürün"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Yuxarıya sağa köçürün"</string>
<string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Aşağıya sola köçürün"</string>
<string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Aşağıya sağa köçürün"</string>
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"İçəri keçirib gizlədin"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Kənara daşıyıb göstərin"</string>
+ <!-- no translation found for accessibility_floating_button_action_remove_menu (6730432848162552135) -->
+ <skip />
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"keçirin"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Cihaz kontrolları"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Kontrol əlavə etmək üçün tətbiq seçin"</string>
@@ -933,6 +948,10 @@
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobil data"</string>
<string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Qoşulub"</string>
+ <!-- no translation found for mobile_data_temp_connection_active (4590222725908806824) -->
+ <skip />
+ <!-- no translation found for mobile_data_poor_connection (819617772268371434) -->
+ <skip />
<string name="mobile_data_off_summary" msgid="3663995422004150567">"Mobil data avtomatik qoşulmayacaq"</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"Bağlantı yoxdur"</string>
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"Heç bir başqa şəbəkə əlçatan deyil"</string>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index ffe49b2..e61b692 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -248,7 +248,8 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Osvetljenost"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Inverzija boja"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Korekcija boja"</string>
- <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Korisnička podešavanja"</string>
+ <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) -->
+ <skip />
<string name="quick_settings_done" msgid="2163641301648855793">"Gotovo"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Zatvori"</string>
<string name="quick_settings_connected" msgid="3873605509184830379">"Povezan"</string>
@@ -727,6 +728,14 @@
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Želite da isključite mobilne podatke?"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"Nećete imati pristup podacima ili internetu preko mobilnog operatera <xliff:g id="CARRIER">%s</xliff:g>. Internet će biti dostupan samo preko WiFi veze."</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"mobilni operater"</string>
+ <!-- no translation found for auto_data_switch_disable_title (5146527155665190652) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_disable_message (5885533647399535852) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_negative_button (2370876875999891444) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_positive_button (8531782041263087564) -->
+ <skip />
<string name="touch_filtered_warning" msgid="8119511393338714836">"Podešavanja ne mogu da verifikuju vaš odgovor jer aplikacija skriva zahtev za dozvolu."</string>
<string name="slice_permission_title" msgid="3262615140094151017">"Želite li da dozvolite aplikaciji <xliff:g id="APP_0">%1$s</xliff:g> da prikazuje isečke iz aplikacije <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
<string name="slice_permission_text_1" msgid="6675965177075443714">"– Može da čita podatke iz aplikacije <xliff:g id="APP">%1$s</xliff:g>"</string>
@@ -785,12 +794,18 @@
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Podešavanja prozora za uvećanje"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Dodirnite za funkcije pristupačnosti. Prilagodite ili zamenite ovo dugme u Podešavanjima.\n\n"<annotation id="link">"Podešavanja"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Pomerite dugme do ivice da biste ga privremeno sakrili"</string>
+ <!-- no translation found for accessibility_floating_button_undo (511112888715708241) -->
+ <skip />
+ <!-- no translation found for accessibility_floating_button_undo_message_text (3044079592757099698) -->
+ <skip />
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Premesti gore levo"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Premesti gore desno"</string>
<string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Premesti dole levo"</string>
<string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Premesti dole desno"</string>
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Premesti do ivice i sakrij"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Premesti izvan ivice i prikaži"</string>
+ <!-- no translation found for accessibility_floating_button_action_remove_menu (6730432848162552135) -->
+ <skip />
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"uključite/isključite"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Kontrole uređaja"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Odaberite aplikaciju za dodavanje kontrola"</string>
@@ -933,6 +948,10 @@
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobilni podaci"</string>
<string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Povezano"</string>
+ <!-- no translation found for mobile_data_temp_connection_active (4590222725908806824) -->
+ <skip />
+ <!-- no translation found for mobile_data_poor_connection (819617772268371434) -->
+ <skip />
<string name="mobile_data_off_summary" msgid="3663995422004150567">"Nije uspelo autom. povezivanje preko mob. podataka"</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"Veza nije uspostavljena"</string>
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"Nije dostupna nijedna druga mreža"</string>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index 3e76985..827370f 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -248,7 +248,8 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Яркасць"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Інверсія колераў"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Карэкцыя колераў"</string>
- <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Налады карыстальніка"</string>
+ <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) -->
+ <skip />
<string name="quick_settings_done" msgid="2163641301648855793">"Гатова"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Закрыць"</string>
<string name="quick_settings_connected" msgid="3873605509184830379">"Падлучана"</string>
@@ -727,6 +728,14 @@
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Выключыць мабільную перадачу даных?"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"У вас не будзе доступу да даных ці інтэрнэту праз аператара <xliff:g id="CARRIER">%s</xliff:g>. Інтэрнэт будзе даступны толькі праз Wi-Fi."</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"ваш аператар"</string>
+ <!-- no translation found for auto_data_switch_disable_title (5146527155665190652) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_disable_message (5885533647399535852) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_negative_button (2370876875999891444) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_positive_button (8531782041263087564) -->
+ <skip />
<string name="touch_filtered_warning" msgid="8119511393338714836">"Праграма хавае запыт на дазвол, таму ваш адказ немагчыма спраўдзіць у Наладах."</string>
<string name="slice_permission_title" msgid="3262615140094151017">"Дазволіць праграме <xliff:g id="APP_0">%1$s</xliff:g> паказваць зрэзы праграмы <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
<string name="slice_permission_text_1" msgid="6675965177075443714">"- Можа счытваць інфармацыю з праграмы <xliff:g id="APP">%1$s</xliff:g>"</string>
@@ -785,12 +794,18 @@
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Налады акна лупы"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Націсніце, каб адкрыць спецыяльныя магчымасці. Рэгулюйце ці замяняйце кнопку ў Наладах.\n\n"<annotation id="link">"Прагляд налад"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Каб часова схаваць кнопку, перамясціце яе на край"</string>
+ <!-- no translation found for accessibility_floating_button_undo (511112888715708241) -->
+ <skip />
+ <!-- no translation found for accessibility_floating_button_undo_message_text (3044079592757099698) -->
+ <skip />
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Перамясціць лявей і вышэй"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Перамясціць правей і вышэй"</string>
<string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Перамясціць лявей і ніжэй"</string>
<string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Перамясціць правей і ніжэй"</string>
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Перамясціць на край і схаваць"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Перамясціць за край і паказаць"</string>
+ <!-- no translation found for accessibility_floating_button_action_remove_menu (6730432848162552135) -->
+ <skip />
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"уключыць/выключыць"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Элементы кіравання прыладай"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Выберыце праграму для дадавання элементаў кіравання"</string>
@@ -933,6 +948,10 @@
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Мабільная перадача даных"</string>
<string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Падключана"</string>
+ <!-- no translation found for mobile_data_temp_connection_active (4590222725908806824) -->
+ <skip />
+ <!-- no translation found for mobile_data_poor_connection (819617772268371434) -->
+ <skip />
<string name="mobile_data_off_summary" msgid="3663995422004150567">"Мабільная перадача даных не ўключаецца аўтаматычна"</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"Няма падключэння"</string>
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"Больш няма даступных сетак"</string>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 572e13f..880445b 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -248,7 +248,8 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Яркост"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Цветове: инверт."</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Корекция на цветове"</string>
- <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Потребителски настройки"</string>
+ <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) -->
+ <skip />
<string name="quick_settings_done" msgid="2163641301648855793">"Готово"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Затваряне"</string>
<string name="quick_settings_connected" msgid="3873605509184830379">"Установена е връзка"</string>
@@ -727,6 +728,14 @@
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Да се изключат ли мобилните данни?"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"Няма да можете да използвате данни или интернет чрез <xliff:g id="CARRIER">%s</xliff:g>. Ще имате достъп до интернет само през Wi-Fi."</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"оператора си"</string>
+ <!-- no translation found for auto_data_switch_disable_title (5146527155665190652) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_disable_message (5885533647399535852) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_negative_button (2370876875999891444) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_positive_button (8531782041263087564) -->
+ <skip />
<string name="touch_filtered_warning" msgid="8119511393338714836">"От Настройки не може да се получи потвърждение за отговора ви, защото заявката за разрешение се прикрива от приложение."</string>
<string name="slice_permission_title" msgid="3262615140094151017">"Искате ли да разрешите на <xliff:g id="APP_0">%1$s</xliff:g> да показва части от <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
<string name="slice_permission_text_1" msgid="6675965177075443714">"– Може да чете информация от <xliff:g id="APP">%1$s</xliff:g>"</string>
@@ -785,12 +794,18 @@
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Настройки за инструмента за увеличаване на прозорци"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Докоснете, за да отворите функциите за достъпност. Персон./заменете бутона от настройките.\n\n"<annotation id="link">"Преглед на настройките"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Преместете бутона до края, за да го скриете временно"</string>
+ <!-- no translation found for accessibility_floating_button_undo (511112888715708241) -->
+ <skip />
+ <!-- no translation found for accessibility_floating_button_undo_message_text (3044079592757099698) -->
+ <skip />
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Преместване горе вляво"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Преместване горе вдясно"</string>
<string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Преместване долу вляво"</string>
<string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Преместване долу вдясно"</string>
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Преместване в края и скриване"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Преместване в края и показване"</string>
+ <!-- no translation found for accessibility_floating_button_action_remove_menu (6730432848162552135) -->
+ <skip />
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"превключване"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Контроли за устройството"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Изберете приложение, за да добавите контроли"</string>
@@ -933,6 +948,10 @@
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Мобилни данни"</string>
<string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Свързано"</string>
+ <!-- no translation found for mobile_data_temp_connection_active (4590222725908806824) -->
+ <skip />
+ <!-- no translation found for mobile_data_poor_connection (819617772268371434) -->
+ <skip />
<string name="mobile_data_off_summary" msgid="3663995422004150567">"Връзката за мобилни данни няма да е автоматична"</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"Няма връзка"</string>
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"Няма други налични мрежи"</string>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index 645f6ab..c74fc69 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -248,7 +248,8 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"উজ্জ্বলতা"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"কালার ইনভার্সন"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"রঙ সংশোধন"</string>
- <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"ব্যবহারকারী সেটিংস"</string>
+ <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) -->
+ <skip />
<string name="quick_settings_done" msgid="2163641301648855793">"সম্পন্ন হয়েছে"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"বন্ধ করুন"</string>
<string name="quick_settings_connected" msgid="3873605509184830379">"সংযুক্ত হয়েছে"</string>
@@ -727,6 +728,14 @@
<string name="mobile_data_disable_title" msgid="5366476131671617790">"মোবাইল ডেটা বন্ধ করবেন?"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"আপনি \'<xliff:g id="CARRIER">%s</xliff:g>\'-এর মাধ্যমে ডেটা অথবা ইন্টারনেট অ্যাক্সেস করতে পারবেন না। শুধুমাত্র ওয়াই-ফাইয়ের মাধ্যমেই ইন্টারনেট অ্যাক্সেস করা যাবে।"</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"আপনার পরিষেবা প্রদানকারী"</string>
+ <!-- no translation found for auto_data_switch_disable_title (5146527155665190652) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_disable_message (5885533647399535852) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_negative_button (2370876875999891444) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_positive_button (8531782041263087564) -->
+ <skip />
<string name="touch_filtered_warning" msgid="8119511393338714836">"একটি অ্যাপ কোনও অনুমোদনের অনুরোধকে ঢেকে দিচ্ছে, তাই সেটিংস থেকে আপনার প্রতিক্রিয়া যাচাই করা যাচ্ছে না।"</string>
<string name="slice_permission_title" msgid="3262615140094151017">"<xliff:g id="APP_0">%1$s</xliff:g> অ্যাপটিকে <xliff:g id="APP_2">%2$s</xliff:g> এর অংশ দেখানোর অনুমতি দেবেন?"</string>
<string name="slice_permission_text_1" msgid="6675965177075443714">"- এটি <xliff:g id="APP">%1$s</xliff:g> এর তথ্য অ্যাক্সেস করতে পারবে"</string>
@@ -785,12 +794,18 @@
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"\'ম্যাগনিফায়ার উইন্ডো\' সেটিংস"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"অ্যাক্সেসিবিলিটি ফিচার খুলতে ট্যাপ করুন। কাস্টমাইজ করুন বা সেটিংসে এই বোতামটি সরিয়ে দিন।\n\n"<annotation id="link">"সেটিংস দেখুন"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"এটি অস্থায়ীভাবে লুকাতে বোতামটি কোণে সরান"</string>
+ <!-- no translation found for accessibility_floating_button_undo (511112888715708241) -->
+ <skip />
+ <!-- no translation found for accessibility_floating_button_undo_message_text (3044079592757099698) -->
+ <skip />
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"উপরে বাঁদিকে সরান"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"উপরে ডানদিকে সরান"</string>
<string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"নিচে বাঁদিকে সরান"</string>
<string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"নিচে ডান দিকে সরান"</string>
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"প্রান্তে যান ও আড়াল করুন"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"প্রান্ত থেকে সরান এবং দেখুন"</string>
+ <!-- no translation found for accessibility_floating_button_action_remove_menu (6730432848162552135) -->
+ <skip />
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"টগল করুন"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"ডিভাইস কন্ট্রোল"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"কন্ট্রোল যোগ করতে অ্যাপ বেছে নিন"</string>
@@ -933,6 +948,10 @@
<string name="mobile_data_settings_title" msgid="3955246641380064901">"মোবাইল ডেটা"</string>
<string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"কানেক্ট করা আছে"</string>
+ <!-- no translation found for mobile_data_temp_connection_active (4590222725908806824) -->
+ <skip />
+ <!-- no translation found for mobile_data_poor_connection (819617772268371434) -->
+ <skip />
<string name="mobile_data_off_summary" msgid="3663995422004150567">"মোবাইল ডেটা নিজে থেকে কানেক্ট হবে না"</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"কানেকশন নেই"</string>
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"অন্য কোনও নেটওয়ার্ক উপলভ্য নেই"</string>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index 183dfe0..5356d74 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -248,7 +248,7 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Osvjetljenje"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Inverzija boja"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Ispravka boja"</string>
- <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Korisničke postavke"</string>
+ <string name="quick_settings_more_user_settings" msgid="7634653308485206306">"Upravljajte korisnicima"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Gotovo"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Zatvori"</string>
<string name="quick_settings_connected" msgid="3873605509184830379">"Povezano"</string>
@@ -727,6 +727,14 @@
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Isključiti prijenos podataka na mobilnoj mreži?"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"Nećete imati pristup podacima ni internetu putem mobilnog operatera <xliff:g id="CARRIER">%s</xliff:g>. Internet će biti dostupan samo putem WiFi-ja."</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"vaš operater"</string>
+ <!-- no translation found for auto_data_switch_disable_title (5146527155665190652) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_disable_message (5885533647399535852) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_negative_button (2370876875999891444) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_positive_button (8531782041263087564) -->
+ <skip />
<string name="touch_filtered_warning" msgid="8119511393338714836">"Postavke ne mogu potvrditi vaš odgovor jer aplikacija zaklanja zahtjev za odobrenje."</string>
<string name="slice_permission_title" msgid="3262615140094151017">"Dozvoliti aplikaciji <xliff:g id="APP_0">%1$s</xliff:g> da prikazuje isječke aplikacije <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
<string name="slice_permission_text_1" msgid="6675965177075443714">"- Može čitati informacije iz aplikacije <xliff:g id="APP">%1$s</xliff:g>"</string>
@@ -785,12 +793,18 @@
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Postavke prozora povećala"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Dodirnite da otvorite funkcije pristupačnosti. Prilagodite ili zamijenite dugme u Postavkama.\n\n"<annotation id="link">"Postavke"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Premjestite dugme do ivice da ga privremeno sakrijete"</string>
+ <!-- no translation found for accessibility_floating_button_undo (511112888715708241) -->
+ <skip />
+ <!-- no translation found for accessibility_floating_button_undo_message_text (3044079592757099698) -->
+ <skip />
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Pomjeranje gore lijevo"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Pomjeranje gore desno"</string>
<string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Pomjeranje dolje lijevo"</string>
<string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Pomjeranje dolje desno"</string>
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Pomjeranje do ivice i sakrivanje"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Pomjeranje izvan ivice i prikaz"</string>
+ <!-- no translation found for accessibility_floating_button_action_remove_menu (6730432848162552135) -->
+ <skip />
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"aktiviranje/deaktiviranje"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Kontrole uređaja"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Odaberite aplikaciju da dodate kontrole"</string>
@@ -933,6 +947,10 @@
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Prijenos podataka na mobilnoj mreži"</string>
<string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Povezano"</string>
+ <!-- no translation found for mobile_data_temp_connection_active (4590222725908806824) -->
+ <skip />
+ <!-- no translation found for mobile_data_poor_connection (819617772268371434) -->
+ <skip />
<string name="mobile_data_off_summary" msgid="3663995422004150567">"Prijenos podataka se neće automatski povezati"</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"Niste povezani s mrežom"</string>
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"Druge mreže nisu dostupne"</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index daa63e6..b61ee2c 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -248,7 +248,8 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Brillantor"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Inversió de colors"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Correcció de color"</string>
- <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Configuració d\'usuari"</string>
+ <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) -->
+ <skip />
<string name="quick_settings_done" msgid="2163641301648855793">"Fet"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Tanca"</string>
<string name="quick_settings_connected" msgid="3873605509184830379">"Connectat"</string>
@@ -727,6 +728,14 @@
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Vols desactivar les dades mòbils?"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"No tindràs accés a dades ni a Internet mitjançant <xliff:g id="CARRIER">%s</xliff:g>. Internet només estarà disponible per Wi-Fi."</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"el teu operador de telefonia mòbil"</string>
+ <!-- no translation found for auto_data_switch_disable_title (5146527155665190652) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_disable_message (5885533647399535852) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_negative_button (2370876875999891444) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_positive_button (8531782041263087564) -->
+ <skip />
<string name="touch_filtered_warning" msgid="8119511393338714836">"Com que hi ha una aplicació que oculta una sol·licitud de permís, no es pot verificar la teva resposta des de la configuració."</string>
<string name="slice_permission_title" msgid="3262615140094151017">"Vols permetre que <xliff:g id="APP_0">%1$s</xliff:g> mostri porcions de l\'aplicació <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
<string name="slice_permission_text_1" msgid="6675965177075443714">"- Pot llegir informació de l\'aplicació <xliff:g id="APP">%1$s</xliff:g>"</string>
@@ -785,12 +794,18 @@
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Configuració de la finestra de la lupa"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Toca per obrir funcions d\'accessibilitat. Personalitza o substitueix el botó a Configuració.\n\n"<annotation id="link">"Mostra"</annotation>"."</string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Mou el botó a l\'extrem per amagar-lo temporalment"</string>
+ <!-- no translation found for accessibility_floating_button_undo (511112888715708241) -->
+ <skip />
+ <!-- no translation found for accessibility_floating_button_undo_message_text (3044079592757099698) -->
+ <skip />
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Mou a dalt a l\'esquerra"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Mou a dalt a la dreta"</string>
<string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Mou a baix a l\'esquerra"</string>
<string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Mou a baix a la dreta"</string>
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Mou dins de les vores i amaga"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Mou fora de les vores i mostra"</string>
+ <!-- no translation found for accessibility_floating_button_action_remove_menu (6730432848162552135) -->
+ <skip />
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"commuta"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Controls de dispositius"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Selecciona l\'aplicació per afegir controls"</string>
@@ -933,6 +948,10 @@
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Dades mòbils"</string>
<string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Connectat"</string>
+ <!-- no translation found for mobile_data_temp_connection_active (4590222725908806824) -->
+ <skip />
+ <!-- no translation found for mobile_data_poor_connection (819617772268371434) -->
+ <skip />
<string name="mobile_data_off_summary" msgid="3663995422004150567">"Les dades mòbils no es connectaran automàticament"</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"Sense connexió"</string>
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"No hi ha cap altra xarxa disponible"</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index cba9448..ee36468 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -248,7 +248,8 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Jas"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Převrácení barev"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Korekce barev"</string>
- <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Uživatelské nastavení"</string>
+ <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) -->
+ <skip />
<string name="quick_settings_done" msgid="2163641301648855793">"Hotovo"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Zavřít"</string>
<string name="quick_settings_connected" msgid="3873605509184830379">"Připojeno"</string>
@@ -727,6 +728,14 @@
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Vypnout mobilní data?"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"Prostřednictvím <xliff:g id="CARRIER">%s</xliff:g> nebudete moci používat data ani internet. Internet bude dostupný pouze přes Wi-Fi."</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"vašeho operátora"</string>
+ <!-- no translation found for auto_data_switch_disable_title (5146527155665190652) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_disable_message (5885533647399535852) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_negative_button (2370876875999891444) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_positive_button (8531782041263087564) -->
+ <skip />
<string name="touch_filtered_warning" msgid="8119511393338714836">"Žádost o oprávnění je blokována jinou aplikací. Nastavení proto vaši odpověď nemůže ověřit."</string>
<string name="slice_permission_title" msgid="3262615140094151017">"Povolit aplikaci <xliff:g id="APP_0">%1$s</xliff:g> zobrazovat ukázky z aplikace <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
<string name="slice_permission_text_1" msgid="6675965177075443714">"– Může číst informace z aplikace <xliff:g id="APP">%1$s</xliff:g>"</string>
@@ -785,12 +794,18 @@
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Nastavení okna zvětšení"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Klepnutím otevřete funkce přístupnosti. Tlačítko lze upravit nebo nahradit v Nastavení.\n\n"<annotation id="link">"Nastavení"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Přesunutím tlačítka k okraji ho dočasně skryjete"</string>
+ <!-- no translation found for accessibility_floating_button_undo (511112888715708241) -->
+ <skip />
+ <!-- no translation found for accessibility_floating_button_undo_message_text (3044079592757099698) -->
+ <skip />
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Přesunout vlevo nahoru"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Přesunout vpravo nahoru"</string>
<string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Přesunout vlevo dolů"</string>
<string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Přesunout vpravo dolů"</string>
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Přesunout k okraji a skrýt"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Přesunout okraj ven a zobrazit"</string>
+ <!-- no translation found for accessibility_floating_button_action_remove_menu (6730432848162552135) -->
+ <skip />
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"přepnout"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Ovládání zařízení"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Vyberte aplikaci, pro kterou chcete přidat ovládací prvky"</string>
@@ -933,6 +948,10 @@
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobilní data"</string>
<string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Připojeno"</string>
+ <!-- no translation found for mobile_data_temp_connection_active (4590222725908806824) -->
+ <skip />
+ <!-- no translation found for mobile_data_poor_connection (819617772268371434) -->
+ <skip />
<string name="mobile_data_off_summary" msgid="3663995422004150567">"Mobilní data se nebudou připojovat automaticky"</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"Žádné připojení"</string>
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"Žádné další sítě nejsou k dispozici"</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index a879cbb..220014e 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -248,7 +248,7 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Lysstyrke"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Ombytning af farver"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Farvekorrigering"</string>
- <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Brugerindstillinger"</string>
+ <string name="quick_settings_more_user_settings" msgid="7634653308485206306">"Administrer brugere"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Udfør"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Luk"</string>
<string name="quick_settings_connected" msgid="3873605509184830379">"Tilsluttet"</string>
@@ -727,6 +727,14 @@
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Vil du deaktivere mobildata?"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"Du vil ikke have data- eller internetadgang via <xliff:g id="CARRIER">%s</xliff:g>. Der vil kun være adgang til internettet via Wi-Fi."</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"dit mobilselskab"</string>
+ <!-- no translation found for auto_data_switch_disable_title (5146527155665190652) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_disable_message (5885533647399535852) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_negative_button (2370876875999891444) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_positive_button (8531782041263087564) -->
+ <skip />
<string name="touch_filtered_warning" msgid="8119511393338714836">"Indstillinger kan ikke bekræfte dit svar, da en app dækker for en anmodning om tilladelse."</string>
<string name="slice_permission_title" msgid="3262615140094151017">"Vil du give <xliff:g id="APP_0">%1$s</xliff:g> tilladelse til at vise eksempler fra <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
<string name="slice_permission_text_1" msgid="6675965177075443714">"- Den kan læse oplysninger fra <xliff:g id="APP">%1$s</xliff:g>"</string>
@@ -785,12 +793,18 @@
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Indstillinger for lupvindue"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Tryk for at åbne hjælpefunktioner. Tilpas eller erstat denne knap i Indstillinger.\n\n"<annotation id="link">"Se indstillingerne"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Flyt knappen til kanten for at skjule den midlertidigt"</string>
+ <!-- no translation found for accessibility_floating_button_undo (511112888715708241) -->
+ <skip />
+ <!-- no translation found for accessibility_floating_button_undo_message_text (3044079592757099698) -->
+ <skip />
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Flyt op til venstre"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Flyt op til højre"</string>
<string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Flyt ned til venstre"</string>
<string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Flyt ned til højre"</string>
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Flyt ud til kanten, og skjul"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Flyt ud til kanten, og vis"</string>
+ <!-- no translation found for accessibility_floating_button_action_remove_menu (6730432848162552135) -->
+ <skip />
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"slå til/fra"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Enhedsstyring"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Vælg en app for at tilføje styring"</string>
@@ -933,6 +947,10 @@
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobildata"</string>
<string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Forbundet"</string>
+ <!-- no translation found for mobile_data_temp_connection_active (4590222725908806824) -->
+ <skip />
+ <!-- no translation found for mobile_data_poor_connection (819617772268371434) -->
+ <skip />
<string name="mobile_data_off_summary" msgid="3663995422004150567">"Ingen automatisk mobildataforbindelse"</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"Der er ingen forbindelse"</string>
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"Der er ingen andre tilgængelige netværk"</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index fb135ff..0b3af67 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -248,7 +248,8 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Helligkeit"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Farbumkehr"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Farbkorrektur"</string>
- <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Nutzereinstellungen"</string>
+ <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) -->
+ <skip />
<string name="quick_settings_done" msgid="2163641301648855793">"Fertig"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Schließen"</string>
<string name="quick_settings_connected" msgid="3873605509184830379">"Verbunden"</string>
@@ -727,6 +728,14 @@
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Mobile Daten deaktivieren?"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"Du kannst dann nicht mehr über <xliff:g id="CARRIER">%s</xliff:g> auf Daten und das Internet zugreifen. Das Internet ist nur noch über WLAN verfügbar."</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"deinen Mobilfunkanbieter"</string>
+ <!-- no translation found for auto_data_switch_disable_title (5146527155665190652) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_disable_message (5885533647399535852) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_negative_button (2370876875999891444) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_positive_button (8531782041263087564) -->
+ <skip />
<string name="touch_filtered_warning" msgid="8119511393338714836">"Deine Eingabe wird von \"Einstellungen\" nicht erkannt, weil die Berechtigungsanfrage von einer App verdeckt wird."</string>
<string name="slice_permission_title" msgid="3262615140094151017">"<xliff:g id="APP_0">%1$s</xliff:g> erlauben, Teile von <xliff:g id="APP_2">%2$s</xliff:g> anzuzeigen?"</string>
<string name="slice_permission_text_1" msgid="6675965177075443714">"– Darf Informationen aus <xliff:g id="APP">%1$s</xliff:g> lesen"</string>
@@ -785,12 +794,18 @@
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Einstellungen für das Vergrößerungsfenster"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Tippe, um die Bedienungshilfen aufzurufen. Du kannst diese Schaltfläche in den Einstellungen anpassen oder ersetzen.\n\n"<annotation id="link">"Zu den Einstellungen"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Durch Ziehen an den Rand wird die Schaltfläche zeitweise ausgeblendet"</string>
+ <!-- no translation found for accessibility_floating_button_undo (511112888715708241) -->
+ <skip />
+ <!-- no translation found for accessibility_floating_button_undo_message_text (3044079592757099698) -->
+ <skip />
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Nach oben links verschieben"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Nach rechts oben verschieben"</string>
<string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Nach unten links verschieben"</string>
<string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Nach unten rechts verschieben"</string>
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"An den Rand verschieben und verbergen"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Vom Rand verschieben und anzeigen"</string>
+ <!-- no translation found for accessibility_floating_button_action_remove_menu (6730432848162552135) -->
+ <skip />
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"Wechseln"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Gerätesteuerung"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"App zum Hinzufügen von Steuerelementen auswählen"</string>
@@ -933,6 +948,10 @@
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobile Daten"</string>
<string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Verbunden"</string>
+ <!-- no translation found for mobile_data_temp_connection_active (4590222725908806824) -->
+ <skip />
+ <!-- no translation found for mobile_data_poor_connection (819617772268371434) -->
+ <skip />
<string name="mobile_data_off_summary" msgid="3663995422004150567">"Keine automatische Verbindung über mobile Daten"</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"Keine Verbindung"</string>
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"Keine anderen Netzwerke verfügbar"</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 3d15953..d707e3e 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -248,7 +248,7 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Φωτεινότητα"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Αντιστροφή χρωμάτων"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Διόρθωση χρωμάτων"</string>
- <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Ρυθμίσεις χρήστη"</string>
+ <string name="quick_settings_more_user_settings" msgid="7634653308485206306">"Διαχείριση χρηστών"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Τέλος"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Κλείσιμο"</string>
<string name="quick_settings_connected" msgid="3873605509184830379">"Συνδέθηκε"</string>
@@ -727,6 +727,14 @@
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Απενεργοποίηση δεδομένων κινητής τηλεφωνίας;"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"Δεν θα έχετε πρόσβαση σε δεδομένα ή στο διαδίκτυο μέσω της εταιρείας κινητής τηλεφωνίας <xliff:g id="CARRIER">%s</xliff:g>. Θα έχετε πρόσβαση στο διαδίκτυο μόνο μέσω Wi-Fi."</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"η εταιρεία κινητής τηλεφωνίας"</string>
+ <!-- no translation found for auto_data_switch_disable_title (5146527155665190652) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_disable_message (5885533647399535852) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_negative_button (2370876875999891444) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_positive_button (8531782041263087564) -->
+ <skip />
<string name="touch_filtered_warning" msgid="8119511393338714836">"Επειδή μια εφαρμογή αποκρύπτει ένα αίτημα άδειας, δεν είναι δυνατή η επαλήθευση της απάντησής σας από τις Ρυθμίσεις."</string>
<string name="slice_permission_title" msgid="3262615140094151017">"Να επιτρέπεται στο <xliff:g id="APP_0">%1$s</xliff:g> να εμφανίζει τμήματα της εφαρμογής <xliff:g id="APP_2">%2$s</xliff:g>;"</string>
<string name="slice_permission_text_1" msgid="6675965177075443714">"- Μπορεί να διαβάζει πληροφορίες από την εφαρμογή <xliff:g id="APP">%1$s</xliff:g>"</string>
@@ -785,12 +793,18 @@
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Ρυθμίσεις παραθύρου μεγεθυντικού φακού"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Πατήστε για άνοιγμα των λειτουργιών προσβασιμότητας. Προσαρμόστε ή αντικαταστήστε το κουμπί στις Ρυθμίσεις.\n\n"<annotation id="link">"Προβολή ρυθμίσεων"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Μετακινήστε το κουμπί στο άκρο για προσωρινή απόκρυψη"</string>
+ <!-- no translation found for accessibility_floating_button_undo (511112888715708241) -->
+ <skip />
+ <!-- no translation found for accessibility_floating_button_undo_message_text (3044079592757099698) -->
+ <skip />
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Μετακίνηση επάνω αριστερά"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Μετακίνηση επάνω δεξιά"</string>
<string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Μετακίνηση κάτω αριστερά"</string>
<string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Μετακίνηση κάτω δεξιά"</string>
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Μετακίν. στο άκρο και απόκρυψη"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Μετακ. εκτός άκρου και εμφάν."</string>
+ <!-- no translation found for accessibility_floating_button_action_remove_menu (6730432848162552135) -->
+ <skip />
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"εναλλαγή"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Στοιχεία ελέγχου συσκευής"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Επιλογή εφαρμογής για προσθήκη στοιχείων ελέγχου"</string>
@@ -933,6 +947,10 @@
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Δεδομένα κινητής τηλεφωνίας"</string>
<string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Συνδέθηκε"</string>
+ <!-- no translation found for mobile_data_temp_connection_active (4590222725908806824) -->
+ <skip />
+ <!-- no translation found for mobile_data_poor_connection (819617772268371434) -->
+ <skip />
<string name="mobile_data_off_summary" msgid="3663995422004150567">"Χωρίς αυτόματη σύνδεση δεδομένων κινητ. τηλεφωνίας"</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"Χωρίς σύνδεση"</string>
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"Δεν υπάρχουν άλλα διαθέσιμα δίκτυα"</string>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index e7166ac..3aaa5f5 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -248,7 +248,7 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Brightness"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Colour inversion"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Colour correction"</string>
- <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"User settings"</string>
+ <string name="quick_settings_more_user_settings" msgid="7634653308485206306">"Manage users"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Done"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Close"</string>
<string name="quick_settings_connected" msgid="3873605509184830379">"Connected"</string>
@@ -727,6 +727,14 @@
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Turn off mobile data?"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"You won\'t have access to data or the Internet through <xliff:g id="CARRIER">%s</xliff:g>. Internet will only be available via Wi-Fi."</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"your operator"</string>
+ <!-- no translation found for auto_data_switch_disable_title (5146527155665190652) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_disable_message (5885533647399535852) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_negative_button (2370876875999891444) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_positive_button (8531782041263087564) -->
+ <skip />
<string name="touch_filtered_warning" msgid="8119511393338714836">"Because an app is obscuring a permission request, Settings can’t verify your response."</string>
<string name="slice_permission_title" msgid="3262615140094151017">"Allow <xliff:g id="APP_0">%1$s</xliff:g> to show <xliff:g id="APP_2">%2$s</xliff:g> slices?"</string>
<string name="slice_permission_text_1" msgid="6675965177075443714">"– It can read information from <xliff:g id="APP">%1$s</xliff:g>"</string>
@@ -785,12 +793,18 @@
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Magnifier window settings"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Tap to open accessibility features. Customise or replace this button in Settings.\n\n"<annotation id="link">"View settings"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Move button to the edge to hide it temporarily"</string>
+ <!-- no translation found for accessibility_floating_button_undo (511112888715708241) -->
+ <skip />
+ <!-- no translation found for accessibility_floating_button_undo_message_text (3044079592757099698) -->
+ <skip />
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Move top left"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Move top right"</string>
<string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Move bottom left"</string>
<string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Move bottom right"</string>
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Move to edge and hide"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Move out edge and show"</string>
+ <!-- no translation found for accessibility_floating_button_action_remove_menu (6730432848162552135) -->
+ <skip />
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"toggle"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Device controls"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Choose app to add controls"</string>
@@ -933,6 +947,10 @@
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobile data"</string>
<string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Connected"</string>
+ <!-- no translation found for mobile_data_temp_connection_active (4590222725908806824) -->
+ <skip />
+ <!-- no translation found for mobile_data_poor_connection (819617772268371434) -->
+ <skip />
<string name="mobile_data_off_summary" msgid="3663995422004150567">"Mobile data won\'t auto‑connect"</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"No connection"</string>
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"No other networks available"</string>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index fe746d9..fb56d9f 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -248,7 +248,7 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Brightness"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Colour inversion"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Colour correction"</string>
- <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"User settings"</string>
+ <string name="quick_settings_more_user_settings" msgid="7634653308485206306">"Manage users"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Done"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Close"</string>
<string name="quick_settings_connected" msgid="3873605509184830379">"Connected"</string>
@@ -727,6 +727,14 @@
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Turn off mobile data?"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"You won\'t have access to data or the Internet through <xliff:g id="CARRIER">%s</xliff:g>. Internet will only be available via Wi-Fi."</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"your carrier"</string>
+ <!-- no translation found for auto_data_switch_disable_title (5146527155665190652) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_disable_message (5885533647399535852) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_negative_button (2370876875999891444) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_positive_button (8531782041263087564) -->
+ <skip />
<string name="touch_filtered_warning" msgid="8119511393338714836">"Because an app is obscuring a permission request, Settings can’t verify your response."</string>
<string name="slice_permission_title" msgid="3262615140094151017">"Allow <xliff:g id="APP_0">%1$s</xliff:g> to show <xliff:g id="APP_2">%2$s</xliff:g> slices?"</string>
<string name="slice_permission_text_1" msgid="6675965177075443714">"– It can read information from <xliff:g id="APP">%1$s</xliff:g>"</string>
@@ -785,12 +793,18 @@
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Magnifier window settings"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Tap to open accessibility features. Customise or replace this button in Settings.\n\n"<annotation id="link">"View settings"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Move button to the edge to hide it temporarily"</string>
+ <!-- no translation found for accessibility_floating_button_undo (511112888715708241) -->
+ <skip />
+ <!-- no translation found for accessibility_floating_button_undo_message_text (3044079592757099698) -->
+ <skip />
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Move top left"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Move top right"</string>
<string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Move bottom left"</string>
<string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Move bottom right"</string>
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Move to edge and hide"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Move out edge and show"</string>
+ <!-- no translation found for accessibility_floating_button_action_remove_menu (6730432848162552135) -->
+ <skip />
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"toggle"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Device controls"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Choose app to add controls"</string>
@@ -933,6 +947,10 @@
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobile data"</string>
<string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Connected"</string>
+ <!-- no translation found for mobile_data_temp_connection_active (4590222725908806824) -->
+ <skip />
+ <!-- no translation found for mobile_data_poor_connection (819617772268371434) -->
+ <skip />
<string name="mobile_data_off_summary" msgid="3663995422004150567">"Mobile data won\'t auto‑connect"</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"No connection"</string>
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"No other networks available"</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index e7166ac..3aaa5f5 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -248,7 +248,7 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Brightness"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Colour inversion"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Colour correction"</string>
- <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"User settings"</string>
+ <string name="quick_settings_more_user_settings" msgid="7634653308485206306">"Manage users"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Done"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Close"</string>
<string name="quick_settings_connected" msgid="3873605509184830379">"Connected"</string>
@@ -727,6 +727,14 @@
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Turn off mobile data?"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"You won\'t have access to data or the Internet through <xliff:g id="CARRIER">%s</xliff:g>. Internet will only be available via Wi-Fi."</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"your operator"</string>
+ <!-- no translation found for auto_data_switch_disable_title (5146527155665190652) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_disable_message (5885533647399535852) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_negative_button (2370876875999891444) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_positive_button (8531782041263087564) -->
+ <skip />
<string name="touch_filtered_warning" msgid="8119511393338714836">"Because an app is obscuring a permission request, Settings can’t verify your response."</string>
<string name="slice_permission_title" msgid="3262615140094151017">"Allow <xliff:g id="APP_0">%1$s</xliff:g> to show <xliff:g id="APP_2">%2$s</xliff:g> slices?"</string>
<string name="slice_permission_text_1" msgid="6675965177075443714">"– It can read information from <xliff:g id="APP">%1$s</xliff:g>"</string>
@@ -785,12 +793,18 @@
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Magnifier window settings"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Tap to open accessibility features. Customise or replace this button in Settings.\n\n"<annotation id="link">"View settings"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Move button to the edge to hide it temporarily"</string>
+ <!-- no translation found for accessibility_floating_button_undo (511112888715708241) -->
+ <skip />
+ <!-- no translation found for accessibility_floating_button_undo_message_text (3044079592757099698) -->
+ <skip />
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Move top left"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Move top right"</string>
<string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Move bottom left"</string>
<string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Move bottom right"</string>
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Move to edge and hide"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Move out edge and show"</string>
+ <!-- no translation found for accessibility_floating_button_action_remove_menu (6730432848162552135) -->
+ <skip />
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"toggle"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Device controls"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Choose app to add controls"</string>
@@ -933,6 +947,10 @@
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobile data"</string>
<string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Connected"</string>
+ <!-- no translation found for mobile_data_temp_connection_active (4590222725908806824) -->
+ <skip />
+ <!-- no translation found for mobile_data_poor_connection (819617772268371434) -->
+ <skip />
<string name="mobile_data_off_summary" msgid="3663995422004150567">"Mobile data won\'t auto‑connect"</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"No connection"</string>
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"No other networks available"</string>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index e7166ac..3aaa5f5 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -248,7 +248,7 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Brightness"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Colour inversion"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Colour correction"</string>
- <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"User settings"</string>
+ <string name="quick_settings_more_user_settings" msgid="7634653308485206306">"Manage users"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Done"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Close"</string>
<string name="quick_settings_connected" msgid="3873605509184830379">"Connected"</string>
@@ -727,6 +727,14 @@
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Turn off mobile data?"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"You won\'t have access to data or the Internet through <xliff:g id="CARRIER">%s</xliff:g>. Internet will only be available via Wi-Fi."</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"your operator"</string>
+ <!-- no translation found for auto_data_switch_disable_title (5146527155665190652) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_disable_message (5885533647399535852) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_negative_button (2370876875999891444) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_positive_button (8531782041263087564) -->
+ <skip />
<string name="touch_filtered_warning" msgid="8119511393338714836">"Because an app is obscuring a permission request, Settings can’t verify your response."</string>
<string name="slice_permission_title" msgid="3262615140094151017">"Allow <xliff:g id="APP_0">%1$s</xliff:g> to show <xliff:g id="APP_2">%2$s</xliff:g> slices?"</string>
<string name="slice_permission_text_1" msgid="6675965177075443714">"– It can read information from <xliff:g id="APP">%1$s</xliff:g>"</string>
@@ -785,12 +793,18 @@
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Magnifier window settings"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Tap to open accessibility features. Customise or replace this button in Settings.\n\n"<annotation id="link">"View settings"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Move button to the edge to hide it temporarily"</string>
+ <!-- no translation found for accessibility_floating_button_undo (511112888715708241) -->
+ <skip />
+ <!-- no translation found for accessibility_floating_button_undo_message_text (3044079592757099698) -->
+ <skip />
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Move top left"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Move top right"</string>
<string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Move bottom left"</string>
<string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Move bottom right"</string>
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Move to edge and hide"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Move out edge and show"</string>
+ <!-- no translation found for accessibility_floating_button_action_remove_menu (6730432848162552135) -->
+ <skip />
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"toggle"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Device controls"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Choose app to add controls"</string>
@@ -933,6 +947,10 @@
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobile data"</string>
<string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Connected"</string>
+ <!-- no translation found for mobile_data_temp_connection_active (4590222725908806824) -->
+ <skip />
+ <!-- no translation found for mobile_data_poor_connection (819617772268371434) -->
+ <skip />
<string name="mobile_data_off_summary" msgid="3663995422004150567">"Mobile data won\'t auto‑connect"</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"No connection"</string>
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"No other networks available"</string>
diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml
index b55b744..ee56838 100644
--- a/packages/SystemUI/res/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings.xml
@@ -248,7 +248,7 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Brightness"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Color inversion"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Color correction"</string>
- <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"User settings"</string>
+ <string name="quick_settings_more_user_settings" msgid="7634653308485206306">"Manage users"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Done"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Close"</string>
<string name="quick_settings_connected" msgid="3873605509184830379">"Connected"</string>
@@ -727,6 +727,10 @@
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Turn off mobile data?"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"You wont have access to data or the internet through <xliff:g id="CARRIER">%s</xliff:g>. Internet will only be available via Wi-Fi."</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"your carrier"</string>
+ <string name="auto_data_switch_disable_title" msgid="5146527155665190652">"Switch back to <xliff:g id="CARRIER">%s</xliff:g>?"</string>
+ <string name="auto_data_switch_disable_message" msgid="5885533647399535852">"Mobile data wont automatically switch based on availability"</string>
+ <string name="auto_data_switch_dialog_negative_button" msgid="2370876875999891444">"No thanks"</string>
+ <string name="auto_data_switch_dialog_positive_button" msgid="8531782041263087564">"Yes, switch"</string>
<string name="touch_filtered_warning" msgid="8119511393338714836">"Because an app is obscuring a permission request, Settings can’t verify your response."</string>
<string name="slice_permission_title" msgid="3262615140094151017">"Allow <xliff:g id="APP_0">%1$s</xliff:g> to show <xliff:g id="APP_2">%2$s</xliff:g> slices?"</string>
<string name="slice_permission_text_1" msgid="6675965177075443714">"- It can read information from <xliff:g id="APP">%1$s</xliff:g>"</string>
@@ -785,12 +789,15 @@
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Magnifier window settings"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Tap to open accessibility features. Customize or replace this button in Settings.\n\n"<annotation id="link">"View settings"</annotation>""</string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Move button to the edge to hide it temporarily"</string>
+ <string name="accessibility_floating_button_undo" msgid="511112888715708241">"Undo"</string>
+ <string name="accessibility_floating_button_undo_message_text" msgid="3044079592757099698">"{count,plural, =1{{label} shortcut removed}other{# shortcuts removed}}"</string>
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Move top left"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Move top right"</string>
<string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Move bottom left"</string>
<string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Move bottom right"</string>
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Move to edge and hide"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Move out edge and show"</string>
+ <string name="accessibility_floating_button_action_remove_menu" msgid="6730432848162552135">"Remove"</string>
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"toggle"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Device controls"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Choose app to add controls"</string>
@@ -933,6 +940,8 @@
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobile data"</string>
<string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Connected"</string>
+ <string name="mobile_data_temp_connection_active" msgid="4590222725908806824">"Temporarily connected"</string>
+ <string name="mobile_data_poor_connection" msgid="819617772268371434">"Poor connection"</string>
<string name="mobile_data_off_summary" msgid="3663995422004150567">"Mobile data won\'t auto‑connect"</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"No connection"</string>
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"No other networks available"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index e7a6cf1..6160caf 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -248,7 +248,8 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Brillo"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Invertir colores"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Corregir colores"</string>
- <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Configuración del usuario"</string>
+ <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) -->
+ <skip />
<string name="quick_settings_done" msgid="2163641301648855793">"Listo"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Cerrar"</string>
<string name="quick_settings_connected" msgid="3873605509184830379">"Conectado"</string>
@@ -727,6 +728,14 @@
<string name="mobile_data_disable_title" msgid="5366476131671617790">"¿Deseas desactivar los datos móviles?"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"No tendrás acceso a datos móviles ni a Internet a través de <xliff:g id="CARRIER">%s</xliff:g>. Solo podrás conectarte a Internet mediante Wi‑Fi."</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"tu proveedor"</string>
+ <!-- no translation found for auto_data_switch_disable_title (5146527155665190652) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_disable_message (5885533647399535852) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_negative_button (2370876875999891444) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_positive_button (8531782041263087564) -->
+ <skip />
<string name="touch_filtered_warning" msgid="8119511393338714836">"Como una app está bloqueando una solicitud de permiso, Configuración no puede verificar tu respuesta."</string>
<string name="slice_permission_title" msgid="3262615140094151017">"¿Permitir que <xliff:g id="APP_0">%1$s</xliff:g> muestre fragmentos de <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
<string name="slice_permission_text_1" msgid="6675965177075443714">"- Puede leer información sobre <xliff:g id="APP">%1$s</xliff:g>"</string>
@@ -785,12 +794,18 @@
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Configuración de la ventana de ampliación"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Presiona para abrir las funciones de accesibilidad. Personaliza o cambia botón en Config.\n\n"<annotation id="link">"Ver config"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Mueve el botón hacia el borde para ocultarlo temporalmente"</string>
+ <!-- no translation found for accessibility_floating_button_undo (511112888715708241) -->
+ <skip />
+ <!-- no translation found for accessibility_floating_button_undo_message_text (3044079592757099698) -->
+ <skip />
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Mover arriba a la izquierda"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Mover arriba a la derecha"</string>
<string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Mover abajo a la izquierda"</string>
<string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Mover abajo a la derecha"</string>
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Mover fuera de borde y ocultar"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Mover fuera de borde y mostrar"</string>
+ <!-- no translation found for accessibility_floating_button_action_remove_menu (6730432848162552135) -->
+ <skip />
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"activar o desactivar"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Controles de dispositivos"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Elige la app para agregar los controles"</string>
@@ -933,6 +948,10 @@
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Datos móviles"</string>
<string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Conexión establecida"</string>
+ <!-- no translation found for mobile_data_temp_connection_active (4590222725908806824) -->
+ <skip />
+ <!-- no translation found for mobile_data_poor_connection (819617772268371434) -->
+ <skip />
<string name="mobile_data_off_summary" msgid="3663995422004150567">"No se conectarán automáticamente los datos móviles"</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"Sin conexión"</string>
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"No hay otras redes disponibles"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index e8218b0..ed9e7d9 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -248,7 +248,8 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Brillo"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Invertir colores"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Corrección de color"</string>
- <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Ajustes de usuario"</string>
+ <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) -->
+ <skip />
<string name="quick_settings_done" msgid="2163641301648855793">"Hecho"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Cerrar"</string>
<string name="quick_settings_connected" msgid="3873605509184830379">"Conectado"</string>
@@ -727,6 +728,14 @@
<string name="mobile_data_disable_title" msgid="5366476131671617790">"¿Desactivar datos móviles?"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"No tendrás acceso a datos móviles ni a Internet a través de <xliff:g id="CARRIER">%s</xliff:g>. Solo podrás conectarte a Internet mediante Wi‑Fi."</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"tu operador"</string>
+ <!-- no translation found for auto_data_switch_disable_title (5146527155665190652) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_disable_message (5885533647399535852) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_negative_button (2370876875999891444) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_positive_button (8531782041263087564) -->
+ <skip />
<string name="touch_filtered_warning" msgid="8119511393338714836">"Una aplicación impide ver una solicitud de permiso, por lo que Ajustes no puede verificar tu respuesta."</string>
<string name="slice_permission_title" msgid="3262615140094151017">"¿Permitir que <xliff:g id="APP_0">%1$s</xliff:g> muestre fragmentos de <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
<string name="slice_permission_text_1" msgid="6675965177075443714">"- Puede leer información de <xliff:g id="APP">%1$s</xliff:g>"</string>
@@ -785,12 +794,18 @@
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Configuración de la ventana de la lupa"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Toca para abrir funciones de accesibilidad. Personaliza o sustituye este botón en Ajustes.\n\n"<annotation id="link">"Ver ajustes"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Mueve el botón hacia el borde para ocultarlo temporalmente"</string>
+ <!-- no translation found for accessibility_floating_button_undo (511112888715708241) -->
+ <skip />
+ <!-- no translation found for accessibility_floating_button_undo_message_text (3044079592757099698) -->
+ <skip />
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Mover arriba a la izquierda"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Mover arriba a la derecha"</string>
<string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Mover abajo a la izquierda"</string>
<string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Mover abajo a la derecha"</string>
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Mover al borde y ocultar"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Mover al borde y mostrar"</string>
+ <!-- no translation found for accessibility_floating_button_action_remove_menu (6730432848162552135) -->
+ <skip />
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"activar/desactivar"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Control de dispositivos"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Elige una aplicación para añadir controles"</string>
@@ -839,7 +854,7 @@
<string name="controls_media_seekbar_description" msgid="4389621713616214611">"<xliff:g id="ELAPSED_TIME">%1$s</xliff:g> de <xliff:g id="TOTAL_TIME">%2$s</xliff:g>"</string>
<string name="controls_media_button_play" msgid="2705068099607410633">"Reproducir"</string>
<string name="controls_media_button_pause" msgid="8614887780950376258">"Pausar"</string>
- <string name="controls_media_button_prev" msgid="8126822360056482970">"Pista anterior"</string>
+ <string name="controls_media_button_prev" msgid="8126822360056482970">"Canción anterior"</string>
<string name="controls_media_button_next" msgid="6662636627525947610">"Siguiente pista"</string>
<string name="controls_media_button_connecting" msgid="3138354625847598095">"Conectando"</string>
<string name="controls_media_smartspace_rec_title" msgid="1699818353932537407">"Reproducir"</string>
@@ -933,6 +948,10 @@
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Datos móviles"</string>
<string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Conectado"</string>
+ <!-- no translation found for mobile_data_temp_connection_active (4590222725908806824) -->
+ <skip />
+ <!-- no translation found for mobile_data_poor_connection (819617772268371434) -->
+ <skip />
<string name="mobile_data_off_summary" msgid="3663995422004150567">"Los datos móviles no se conectarán automáticamente"</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"Sin conexión"</string>
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"No hay otras redes disponibles"</string>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index 11a9dc9..417c2c2 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -248,7 +248,8 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Heledus"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Värvide ümberpööramine"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Värviparandus"</string>
- <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Kasutaja seaded"</string>
+ <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) -->
+ <skip />
<string name="quick_settings_done" msgid="2163641301648855793">"Valmis"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Sule"</string>
<string name="quick_settings_connected" msgid="3873605509184830379">"Ühendatud"</string>
@@ -727,6 +728,14 @@
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Kas lülitada mobiilne andmeside välja?"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"Pärast seda pole teil operaatori <xliff:g id="CARRIER">%s</xliff:g> kaudu juurdepääsu andmesidele ega internetile. Internet on saadaval ainult WiFi kaudu."</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"teie operaator"</string>
+ <!-- no translation found for auto_data_switch_disable_title (5146527155665190652) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_disable_message (5885533647399535852) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_negative_button (2370876875999891444) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_positive_button (8531782041263087564) -->
+ <skip />
<string name="touch_filtered_warning" msgid="8119511393338714836">"Seaded ei saa teie vastust kinnitada, sest rakendus varjab loataotlust."</string>
<string name="slice_permission_title" msgid="3262615140094151017">"Kas lubada rakendusel <xliff:g id="APP_0">%1$s</xliff:g> näidata rakenduse <xliff:g id="APP_2">%2$s</xliff:g> lõike?"</string>
<string name="slice_permission_text_1" msgid="6675965177075443714">"- See saab lugeda teavet rakendusest <xliff:g id="APP">%1$s</xliff:g>"</string>
@@ -785,12 +794,18 @@
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Luubi akna seaded"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Puudutage juurdepääsufunktsioonide avamiseks. Kohandage nuppu või asendage see seadetes.\n\n"<annotation id="link">"Kuva seaded"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Teisaldage nupp serva, et see ajutiselt peita"</string>
+ <!-- no translation found for accessibility_floating_button_undo (511112888715708241) -->
+ <skip />
+ <!-- no translation found for accessibility_floating_button_undo_message_text (3044079592757099698) -->
+ <skip />
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Teisalda üles vasakule"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Teisalda üles paremale"</string>
<string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Teisalda alla vasakule"</string>
<string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Teisalda alla paremale"</string>
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Teisalda serva ja kuva"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Teisalda servast eemale ja kuva"</string>
+ <!-- no translation found for accessibility_floating_button_action_remove_menu (6730432848162552135) -->
+ <skip />
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"lülita"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Seadmete juhikud"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Valige juhtelementide lisamiseks rakendus"</string>
@@ -933,6 +948,10 @@
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobiilne andmeside"</string>
<string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Ühendatud"</string>
+ <!-- no translation found for mobile_data_temp_connection_active (4590222725908806824) -->
+ <skip />
+ <!-- no translation found for mobile_data_poor_connection (819617772268371434) -->
+ <skip />
<string name="mobile_data_off_summary" msgid="3663995422004150567">"Mobiilset andmesideühendust ei looda automaatselt"</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"Ühendus puudub"</string>
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"Ühtegi muud võrku pole saadaval"</string>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index 3714781..ee1ba23 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -248,7 +248,8 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Distira"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Kolore-alderantzikatzea"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Koloreen zuzenketa"</string>
- <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Erabiltzaile-ezarpenak"</string>
+ <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) -->
+ <skip />
<string name="quick_settings_done" msgid="2163641301648855793">"Eginda"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Itxi"</string>
<string name="quick_settings_connected" msgid="3873605509184830379">"Konektatuta"</string>
@@ -727,6 +728,14 @@
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Datu-konexioa desaktibatu nahi duzu?"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"<xliff:g id="CARRIER">%s</xliff:g> erabilita ezingo dituzu erabili datuak edo Internet. Wifi-sare baten bidez soilik konektatu ahal izango zara Internetera."</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"Zure operadorea"</string>
+ <!-- no translation found for auto_data_switch_disable_title (5146527155665190652) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_disable_message (5885533647399535852) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_negative_button (2370876875999891444) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_positive_button (8531782041263087564) -->
+ <skip />
<string name="touch_filtered_warning" msgid="8119511393338714836">"Aplikazio bat baimen-eskaera oztopatzen ari denez, ezarpenek ezin dute egiaztatu erantzuna."</string>
<string name="slice_permission_title" msgid="3262615140094151017">"<xliff:g id="APP_2">%2$s</xliff:g> aplikazioaren zatiak erakusteko baimena eman nahi diozu <xliff:g id="APP_0">%1$s</xliff:g> aplikazioari?"</string>
<string name="slice_permission_text_1" msgid="6675965177075443714">"- <xliff:g id="APP">%1$s</xliff:g> aplikazioaren informazioa irakur dezake."</string>
@@ -785,12 +794,18 @@
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Luparen leihoaren ezarpenak"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Erabilerraztasun-eginbideak irekitzeko, sakatu hau. Ezarpenetan pertsonalizatu edo ordez dezakezu botoia.\n\n"<annotation id="link">"Ikusi ezarpenak"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Eraman botoia ertzera aldi baterako ezkutatzeko"</string>
+ <!-- no translation found for accessibility_floating_button_undo (511112888715708241) -->
+ <skip />
+ <!-- no translation found for accessibility_floating_button_undo_message_text (3044079592757099698) -->
+ <skip />
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Eraman goialdera, ezkerretara"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Eraman goialdera, eskuinetara"</string>
<string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Eraman behealdera, ezkerretara"</string>
<string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Eraman behealdera, eskuinetara"</string>
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Eraman ertzera eta ezkutatu"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Atera ertzetik eta erakutsi"</string>
+ <!-- no translation found for accessibility_floating_button_action_remove_menu (6730432848162552135) -->
+ <skip />
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"aldatu"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Gailuak kontrolatzeko widgetak"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Aukeratu aplikazio bat kontrolatzeko aukerak gehitzeko"</string>
@@ -933,6 +948,10 @@
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Datu-konexioa"</string>
<string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> (<xliff:g id="NETWORKMODE">%2$s</xliff:g>)"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Konektatuta"</string>
+ <!-- no translation found for mobile_data_temp_connection_active (4590222725908806824) -->
+ <skip />
+ <!-- no translation found for mobile_data_poor_connection (819617772268371434) -->
+ <skip />
<string name="mobile_data_off_summary" msgid="3663995422004150567">"Ez da automatikoki aktibatuko datu-konexioa"</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"Konexiorik gabe"</string>
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"Ez dago beste sare erabilgarririk"</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 183a9ed..62d73ae 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -248,7 +248,8 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"روشنایی"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"وارونگی رنگ"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"تصحیح رنگ"</string>
- <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"تنظیمات کاربر"</string>
+ <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) -->
+ <skip />
<string name="quick_settings_done" msgid="2163641301648855793">"تمام"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"بستن"</string>
<string name="quick_settings_connected" msgid="3873605509184830379">"متصل"</string>
@@ -727,6 +728,14 @@
<string name="mobile_data_disable_title" msgid="5366476131671617790">"داده تلفن همراه خاموش شود؟"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"نمیتوانید ازطریق <xliff:g id="CARRIER">%s</xliff:g> به داده یا اینترنت دسترسی داشته باشید. اینترنت فقط ازطریق Wi-Fi در دسترس خواهد بود."</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"شرکت مخابراتی شما"</string>
+ <!-- no translation found for auto_data_switch_disable_title (5146527155665190652) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_disable_message (5885533647399535852) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_negative_button (2370876875999891444) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_positive_button (8531782041263087564) -->
+ <skip />
<string name="touch_filtered_warning" msgid="8119511393338714836">"چون برنامهای درحال ایجاد تداخل در درخواست مجوز است، «تنظیمات» نمیتواند پاسخ شما را تأیید کند."</string>
<string name="slice_permission_title" msgid="3262615140094151017">"به <xliff:g id="APP_0">%1$s</xliff:g> اجازه داده شود تکههای <xliff:g id="APP_2">%2$s</xliff:g> را نشان دهد؟"</string>
<string name="slice_permission_text_1" msgid="6675965177075443714">"- میتواند اطلاعات <xliff:g id="APP">%1$s</xliff:g> را بخواند"</string>
@@ -785,12 +794,18 @@
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"تنظیمات پنجره ذرهبین"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"برای باز کردن ویژگیهای دسترسپذیری ضربه بزنید. در تنظیمات این دکمه را سفارشی یا جایگزین کنید\n\n"<annotation id="link">"تنظیمات"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"برای پنهان کردن موقتی دکمه، آن را به لبه ببرید"</string>
+ <!-- no translation found for accessibility_floating_button_undo (511112888715708241) -->
+ <skip />
+ <!-- no translation found for accessibility_floating_button_undo_message_text (3044079592757099698) -->
+ <skip />
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"انتقال به بالا سمت راست"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"انتقال به بالا سمت چپ"</string>
<string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"انتقال به پایین سمت راست"</string>
<string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"انتقال به پایین سمت چپ"</string>
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"انتقال به لبه و پنهان کردن"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"انتقال به خارج از لبه و نمایش"</string>
+ <!-- no translation found for accessibility_floating_button_action_remove_menu (6730432848162552135) -->
+ <skip />
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"روشن/ خاموش کردن"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"کنترلهای دستگاه"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"انتخاب برنامه برای افزودن کنترلها"</string>
@@ -933,6 +948,10 @@
<string name="mobile_data_settings_title" msgid="3955246641380064901">"داده تلفن همراه"</string>
<string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"متصل است"</string>
+ <!-- no translation found for mobile_data_temp_connection_active (4590222725908806824) -->
+ <skip />
+ <!-- no translation found for mobile_data_poor_connection (819617772268371434) -->
+ <skip />
<string name="mobile_data_off_summary" msgid="3663995422004150567">"داده تلفن همراه بهطور خودکار متصل نخواهد شد"</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"اتصال برقرار نیست"</string>
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"شبکه دیگری وجود ندارد"</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index df05015..bfb450f 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -248,7 +248,8 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Kirkkaus"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Käänteiset värit"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Värinkorjaus"</string>
- <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Käyttäjäasetukset"</string>
+ <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) -->
+ <skip />
<string name="quick_settings_done" msgid="2163641301648855793">"Valmis"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Sulje"</string>
<string name="quick_settings_connected" msgid="3873605509184830379">"Yhdistetty"</string>
@@ -727,6 +728,14 @@
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Laitetaanko mobiilidata pois päältä?"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"<xliff:g id="CARRIER">%s</xliff:g> ei enää tarjoa pääsyä dataan eikä internetyhteyttä, joka on saatavilla vain Wi-Fin kautta."</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"operaattorisi"</string>
+ <!-- no translation found for auto_data_switch_disable_title (5146527155665190652) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_disable_message (5885533647399535852) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_negative_button (2370876875999891444) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_positive_button (8531782041263087564) -->
+ <skip />
<string name="touch_filtered_warning" msgid="8119511393338714836">"Sovellus peittää käyttöoikeuspyynnön, joten Asetukset ei voi vahvistaa valintaasi."</string>
<string name="slice_permission_title" msgid="3262615140094151017">"Saako <xliff:g id="APP_0">%1$s</xliff:g> näyttää osia sovelluksesta <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
<string name="slice_permission_text_1" msgid="6675965177075443714">"– Se voi lukea tietoja sovelluksesta <xliff:g id="APP">%1$s</xliff:g>."</string>
@@ -785,12 +794,18 @@
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Ikkunan suurennuksen asetukset"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Avaa esteettömyysominaisuudet napauttamalla. Yksilöi tai vaihda painike asetuksista.\n\n"<annotation id="link">"Avaa asetukset"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Piilota painike tilapäisesti siirtämällä se reunaan"</string>
+ <!-- no translation found for accessibility_floating_button_undo (511112888715708241) -->
+ <skip />
+ <!-- no translation found for accessibility_floating_button_undo_message_text (3044079592757099698) -->
+ <skip />
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Siirrä vasempaan yläreunaan"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Siirrä oikeaan yläreunaan"</string>
<string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Siirrä vasempaan alareunaan"</string>
<string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Siirrä oikeaan alareunaan"</string>
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Siirrä reunaan ja piilota"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Siirrä pois reunasta ja näytä"</string>
+ <!-- no translation found for accessibility_floating_button_action_remove_menu (6730432848162552135) -->
+ <skip />
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"vaihda"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Laitehallinta"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Valitse sovellus lisätäksesi säätimiä"</string>
@@ -933,6 +948,10 @@
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobiilidata"</string>
<string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Yhdistetty"</string>
+ <!-- no translation found for mobile_data_temp_connection_active (4590222725908806824) -->
+ <skip />
+ <!-- no translation found for mobile_data_poor_connection (819617772268371434) -->
+ <skip />
<string name="mobile_data_off_summary" msgid="3663995422004150567">"Mobiilidata ei yhdisty automaattisesti"</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"Ei yhteyttä"</string>
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"Ei muita verkkoja käytettävissä"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index c5c941b..b2d925c 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -248,7 +248,8 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Luminosité"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Inversion des couleurs"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Correction des couleurs"</string>
- <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Paramètres utilisateur"</string>
+ <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) -->
+ <skip />
<string name="quick_settings_done" msgid="2163641301648855793">"Terminé"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Fermer"</string>
<string name="quick_settings_connected" msgid="3873605509184830379">"Connecté"</string>
@@ -727,6 +728,14 @@
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Désactiver les données cellulaires?"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"Vous n\'aurez pas accès aux données ni à Internet avec <xliff:g id="CARRIER">%s</xliff:g>. Vous ne pourrez accéder à Internet que par Wi-Fi."</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"votre fournisseur de services"</string>
+ <!-- no translation found for auto_data_switch_disable_title (5146527155665190652) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_disable_message (5885533647399535852) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_negative_button (2370876875999891444) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_positive_button (8531782041263087564) -->
+ <skip />
<string name="touch_filtered_warning" msgid="8119511393338714836">"Une application obscurcit une demande d\'autorisation, alors Paramètres ne peut pas vérifier votre réponse."</string>
<string name="slice_permission_title" msgid="3262615140094151017">"Autoriser <xliff:g id="APP_0">%1$s</xliff:g> à afficher <xliff:g id="APP_2">%2$s</xliff:g> tranches?"</string>
<string name="slice_permission_text_1" msgid="6675965177075443714">"- Il peut lire de l\'information de <xliff:g id="APP">%1$s</xliff:g>"</string>
@@ -785,12 +794,18 @@
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Paramètres de la fenêtre de loupe"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Touchez pour ouvrir fonction. d\'access. Personnalisez ou remplacez bouton dans Param.\n\n"<annotation id="link">"Afficher param."</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Déplacez le bouton vers le bord pour le masquer temporairement"</string>
+ <!-- no translation found for accessibility_floating_button_undo (511112888715708241) -->
+ <skip />
+ <!-- no translation found for accessibility_floating_button_undo_message_text (3044079592757099698) -->
+ <skip />
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Déplacer dans coin sup. gauche"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Déplacer dans coin sup. droit"</string>
<string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Déplacer dans coin inf. gauche"</string>
<string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Déplacer dans coin inf. droit"</string>
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Éloigner du bord et masquer"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Éloigner du bord et afficher"</string>
+ <!-- no translation found for accessibility_floating_button_action_remove_menu (6730432848162552135) -->
+ <skip />
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"basculer"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Commandes des appareils"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Sélectionnez l\'application pour laquelle ajouter des commandes"</string>
@@ -933,6 +948,10 @@
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Données cellulaires"</string>
<string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Connexion active"</string>
+ <!-- no translation found for mobile_data_temp_connection_active (4590222725908806824) -->
+ <skip />
+ <!-- no translation found for mobile_data_poor_connection (819617772268371434) -->
+ <skip />
<string name="mobile_data_off_summary" msgid="3663995422004150567">"Aucune connexion auto. des données cellulaires"</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"Aucune connexion"</string>
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"Aucun autre réseau n\'est accessible"</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 1a2b877..12a88c6 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -248,7 +248,8 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Luminosité"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Inversion des couleurs"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Correction des couleurs"</string>
- <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Paramètres utilisateur"</string>
+ <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) -->
+ <skip />
<string name="quick_settings_done" msgid="2163641301648855793">"OK"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Fermer"</string>
<string name="quick_settings_connected" msgid="3873605509184830379">"Connecté"</string>
@@ -727,6 +728,14 @@
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Désactiver les données mobiles ?"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"Vous n\'aurez pas accès aux données mobiles ni à Internet via <xliff:g id="CARRIER">%s</xliff:g>. Vous ne pourrez accéder à Internet que par Wi-Fi."</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"votre opérateur"</string>
+ <!-- no translation found for auto_data_switch_disable_title (5146527155665190652) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_disable_message (5885533647399535852) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_negative_button (2370876875999891444) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_positive_button (8531782041263087564) -->
+ <skip />
<string name="touch_filtered_warning" msgid="8119511393338714836">"L\'application Paramètres ne peut pas valider votre réponse, car une application masque la demande d\'autorisation."</string>
<string name="slice_permission_title" msgid="3262615140094151017">"Autoriser <xliff:g id="APP_0">%1$s</xliff:g> à afficher des éléments de <xliff:g id="APP_2">%2$s</xliff:g> ?"</string>
<string name="slice_permission_text_1" msgid="6675965177075443714">"- Accès aux informations de <xliff:g id="APP">%1$s</xliff:g>"</string>
@@ -785,12 +794,18 @@
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Paramètres de la fenêtre d\'agrandissement"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Appuyez pour ouvrir fonctionnalités d\'accessibilité. Personnalisez ou remplacez bouton dans paramètres.\n\n"<annotation id="link">"Voir paramètres"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Déplacer le bouton vers le bord pour le masquer temporairement"</string>
+ <!-- no translation found for accessibility_floating_button_undo (511112888715708241) -->
+ <skip />
+ <!-- no translation found for accessibility_floating_button_undo_message_text (3044079592757099698) -->
+ <skip />
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Déplacer en haut à gauche"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Déplacer en haut à droite"</string>
<string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Déplacer en bas à gauche"</string>
<string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Déplacer en bas à droite"</string>
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Rapprocher du bord et masquer"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Éloigner du bord et afficher"</string>
+ <!-- no translation found for accessibility_floating_button_action_remove_menu (6730432848162552135) -->
+ <skip />
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"activer/désactiver"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Commandes des appareils"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Sélectionnez l\'appli pour laquelle ajouter des commandes"</string>
@@ -933,6 +948,10 @@
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Données mobiles"</string>
<string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Connecté"</string>
+ <!-- no translation found for mobile_data_temp_connection_active (4590222725908806824) -->
+ <skip />
+ <!-- no translation found for mobile_data_poor_connection (819617772268371434) -->
+ <skip />
<string name="mobile_data_off_summary" msgid="3663995422004150567">"Pas de connexion automatique des données mobiles"</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"Aucune connexion"</string>
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"Aucun autre réseau disponible"</string>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index e5def1e..d18d596 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -248,7 +248,8 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Brillo"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Inversión da cor"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Corrección da cor"</string>
- <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Configuración de usuario"</string>
+ <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) -->
+ <skip />
<string name="quick_settings_done" msgid="2163641301648855793">"Feito"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Pechar"</string>
<string name="quick_settings_connected" msgid="3873605509184830379">"Conectado"</string>
@@ -727,6 +728,14 @@
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Queres desactivar os datos móbiles?"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"Non terás acceso aos datos nin a Internet a través de <xliff:g id="CARRIER">%s</xliff:g>. Internet só estará dispoñible mediante a wifi."</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"o teu operador"</string>
+ <!-- no translation found for auto_data_switch_disable_title (5146527155665190652) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_disable_message (5885533647399535852) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_negative_button (2370876875999891444) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_positive_button (8531782041263087564) -->
+ <skip />
<string name="touch_filtered_warning" msgid="8119511393338714836">"Dado que unha aplicación se superpón sobre unha solicitude de permiso, a configuración non pode verificar a túa resposta."</string>
<string name="slice_permission_title" msgid="3262615140094151017">"Queres permitir que <xliff:g id="APP_0">%1$s</xliff:g> mostre fragmentos de aplicación de <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
<string name="slice_permission_text_1" msgid="6675965177075443714">"- Pode ler información da aplicación <xliff:g id="APP">%1$s</xliff:g>"</string>
@@ -785,12 +794,18 @@
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Configuración da ventá da lupa"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Toca para abrir as funcións de accesibilidade. Cambia este botón en Configuración.\n\n"<annotation id="link">"Ver configuración"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Para ocultar temporalmente o botón, móveo ata o bordo"</string>
+ <!-- no translation found for accessibility_floating_button_undo (511112888715708241) -->
+ <skip />
+ <!-- no translation found for accessibility_floating_button_undo_message_text (3044079592757099698) -->
+ <skip />
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Mover á parte super. esquerda"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Mover á parte superior dereita"</string>
<string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Mover á parte infer. esquerda"</string>
<string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Mover á parte inferior dereita"</string>
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Mover ao bordo e ocultar"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Mover fóra do bordo e mostrar"</string>
+ <!-- no translation found for accessibility_floating_button_action_remove_menu (6730432848162552135) -->
+ <skip />
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"activar/desactivar"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Control de dispositivos"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Escolle unha aplicación para engadir controis"</string>
@@ -933,6 +948,10 @@
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Datos móbiles"</string>
<string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Conectada"</string>
+ <!-- no translation found for mobile_data_temp_connection_active (4590222725908806824) -->
+ <skip />
+ <!-- no translation found for mobile_data_poor_connection (819617772268371434) -->
+ <skip />
<string name="mobile_data_off_summary" msgid="3663995422004150567">"Os datos móbiles non se conectarán automaticamente"</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"Sen conexión"</string>
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"Non hai outras redes dispoñibles"</string>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index 552b049..034c161 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -248,7 +248,8 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"તેજ"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"વિપરીત રંગમાં બદલવું"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"રંગ સુધારણા"</string>
- <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"વપરાશકર્તા સેટિંગ"</string>
+ <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) -->
+ <skip />
<string name="quick_settings_done" msgid="2163641301648855793">"થઈ ગયું"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"બંધ કરો"</string>
<string name="quick_settings_connected" msgid="3873605509184830379">"કનેક્ટ થયેલું"</string>
@@ -727,6 +728,14 @@
<string name="mobile_data_disable_title" msgid="5366476131671617790">"મોબાઇલ ડેટા બંધ કરીએ?"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"તમને <xliff:g id="CARRIER">%s</xliff:g> મારફતે ડેટા અથવા ઇન્ટરનેટનો ઍક્સેસ મળશે નહીં. ઇન્ટરનેટ માત્ર વાઇ-ફાઇ દ્વારા ઉપલબ્ધ થશે."</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"તમારા કૅરિઅર"</string>
+ <!-- no translation found for auto_data_switch_disable_title (5146527155665190652) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_disable_message (5885533647399535852) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_negative_button (2370876875999891444) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_positive_button (8531782041263087564) -->
+ <skip />
<string name="touch_filtered_warning" msgid="8119511393338714836">"કોઈ ઍપ પરવાનગી વિનંતીને અસ્પષ્ટ કરતી હોવાને કારણે, સેટિંગ તમારા પ્રતિસાદને ચકાસી શકતું નથી."</string>
<string name="slice_permission_title" msgid="3262615140094151017">"<xliff:g id="APP_0">%1$s</xliff:g>ને <xliff:g id="APP_2">%2$s</xliff:g> સ્લાઇસ બતાવવાની મંજૂરી આપીએ?"</string>
<string name="slice_permission_text_1" msgid="6675965177075443714">"- મારાથી <xliff:g id="APP">%1$s</xliff:g>ની માહિતી વાંચી શકાતી નથી"</string>
@@ -785,12 +794,18 @@
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"મેગ્નિફાયર વિન્ડોના સેટિંગ"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"ઍક્સેસિબિલિટી સુવિધાઓ ખોલવા માટે ટૅપ કરો. સેટિંગમાં આ બટનને કસ્ટમાઇઝ કરો અથવા બદલો.\n\n"<annotation id="link">"સેટિંગ જુઓ"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"તેને હંગામી રૂપે ખસેડવા માટે બટનને કિનારી પર ખસેડો"</string>
+ <!-- no translation found for accessibility_floating_button_undo (511112888715708241) -->
+ <skip />
+ <!-- no translation found for accessibility_floating_button_undo_message_text (3044079592757099698) -->
+ <skip />
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"ઉપર ડાબે ખસેડો"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"ઉપર જમણે ખસેડો"</string>
<string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"નીચે ડાબે ખસેડો"</string>
<string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"નીચે જમણે ખસેડો"</string>
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"કિનારી પર ખસેડો અને છુપાવો"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"કિનારીથી ખસેડો અને બતાવો"</string>
+ <!-- no translation found for accessibility_floating_button_action_remove_menu (6730432848162552135) -->
+ <skip />
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"ટૉગલ કરો"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"ડિવાઇસનાં નિયંત્રણો"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"નિયંત્રણો ઉમેરવા માટે ઍપ પસંદ કરો"</string>
@@ -933,6 +948,10 @@
<string name="mobile_data_settings_title" msgid="3955246641380064901">"મોબાઇલ ડેટા"</string>
<string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"કનેક્ટ કરેલું"</string>
+ <!-- no translation found for mobile_data_temp_connection_active (4590222725908806824) -->
+ <skip />
+ <!-- no translation found for mobile_data_poor_connection (819617772268371434) -->
+ <skip />
<string name="mobile_data_off_summary" msgid="3663995422004150567">"મોબાઇલ ડેટા ઑટોમૅટિક રીતે કનેક્ટ થશે નહીં"</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"કોઈ કનેક્શન નથી"</string>
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"બીજાં કોઈ નેટવર્ક ઉપલબ્ધ નથી"</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index c0052d6..dc94a8d 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -248,7 +248,8 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"स्क्रीन की रोशनी"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"रंग बदलने की सुविधा"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"रंग में सुधार करने की सुविधा"</string>
- <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"उपयोगकर्ता सेटिंग"</string>
+ <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) -->
+ <skip />
<string name="quick_settings_done" msgid="2163641301648855793">"हो गया"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"रद्द करें"</string>
<string name="quick_settings_connected" msgid="3873605509184830379">"कनेक्ट है"</string>
@@ -727,6 +728,14 @@
<string name="mobile_data_disable_title" msgid="5366476131671617790">"मोबाइल डेटा बंद करना चाहते हैं?"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"आप <xliff:g id="CARRIER">%s</xliff:g> से डेटा या इंटरनेट का इस्तेमाल नहीं कर पाएंगे. इंटरनेट सिर्फ़ वाई-फ़ाई से चलेगा."</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"आपको मोबाइल और इंटरनेट सेवा देने वाली कंपनी"</string>
+ <!-- no translation found for auto_data_switch_disable_title (5146527155665190652) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_disable_message (5885533647399535852) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_negative_button (2370876875999891444) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_positive_button (8531782041263087564) -->
+ <skip />
<string name="touch_filtered_warning" msgid="8119511393338714836">"ऐप की वजह से मंज़ूरी के अनुरोध को समझने में दिक्कत हो रही है, इसलिए सेटिंग से आपके जवाब की पुष्टि नहीं हो पा रही है."</string>
<string name="slice_permission_title" msgid="3262615140094151017">"<xliff:g id="APP_0">%1$s</xliff:g> को <xliff:g id="APP_2">%2$s</xliff:g> के हिस्से (स्लाइस) दिखाने की मंज़ूरी दें?"</string>
<string name="slice_permission_text_1" msgid="6675965177075443714">"- यह <xliff:g id="APP">%1$s</xliff:g> से सूचना पढ़ सकता है"</string>
@@ -785,12 +794,18 @@
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"ज़ूम करने की सुविधा वाली विंडो से जुड़ी सेटिंग"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"सुलभता सुविधाएं खोलने के लिए टैप करें. सेटिंग में, इस बटन को बदलें या अपने हिसाब से सेट करें.\n\n"<annotation id="link">"सेटिंग देखें"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"बटन को कुछ समय छिपाने के लिए, उसे किनारे पर ले जाएं"</string>
+ <!-- no translation found for accessibility_floating_button_undo (511112888715708241) -->
+ <skip />
+ <!-- no translation found for accessibility_floating_button_undo_message_text (3044079592757099698) -->
+ <skip />
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"सबसे ऊपर बाईं ओर ले जाएं"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"सबसे ऊपर दाईं ओर ले जाएं"</string>
<string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"सबसे नीचे बाईं ओर ले जाएं"</string>
<string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"सबसे नीचे दाईं ओर ले जाएं"</string>
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"एज पर ले जाएं और छिपाएं"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"एज से निकालें और दिखाएं"</string>
+ <!-- no translation found for accessibility_floating_button_action_remove_menu (6730432848162552135) -->
+ <skip />
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"टॉगल करें"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"डिवाइस कंट्रोल"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"कंट्रोल जोड़ने के लिए ऐप्लिकेशन चुनें"</string>
@@ -933,6 +948,10 @@
<string name="mobile_data_settings_title" msgid="3955246641380064901">"मोबाइल डेटा"</string>
<string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"कनेक्ट हो गया"</string>
+ <!-- no translation found for mobile_data_temp_connection_active (4590222725908806824) -->
+ <skip />
+ <!-- no translation found for mobile_data_poor_connection (819617772268371434) -->
+ <skip />
<string name="mobile_data_off_summary" msgid="3663995422004150567">"मोबाइल डेटा अपने-आप कनेक्ट नहीं होगा"</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"इंटरनेट कनेक्शन नहीं है"</string>
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"कोई दूसरा नेटवर्क उपलब्ध नहीं है"</string>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 60f0c8a..be5253f 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -248,7 +248,7 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Svjetlina"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Inverzija boja"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Korekcija boja"</string>
- <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Korisničke postavke"</string>
+ <string name="quick_settings_more_user_settings" msgid="7634653308485206306">"Upravljajte korisnicima"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Gotovo"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Zatvori"</string>
<string name="quick_settings_connected" msgid="3873605509184830379">"Povezano"</string>
@@ -727,6 +727,14 @@
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Isključiti mobilne podatke?"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"Nećete imati pristup mobilnim podacima ili internetu putem operatera <xliff:g id="CARRIER">%s</xliff:g>. Internet će biti dostupan samo putem Wi-Fija."</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"vaš mobilni operater"</string>
+ <!-- no translation found for auto_data_switch_disable_title (5146527155665190652) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_disable_message (5885533647399535852) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_negative_button (2370876875999891444) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_positive_button (8531782041263087564) -->
+ <skip />
<string name="touch_filtered_warning" msgid="8119511393338714836">"Budući da aplikacija prekriva zahtjev za dopuštenje, Postavke ne mogu potvrditi vaš odgovor."</string>
<string name="slice_permission_title" msgid="3262615140094151017">"Želite li dopustiti aplikaciji <xliff:g id="APP_0">%1$s</xliff:g> da prikazuje isječke aplikacije <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
<string name="slice_permission_text_1" msgid="6675965177075443714">"– može čitati informacije aplikacije <xliff:g id="APP">%1$s</xliff:g>"</string>
@@ -785,12 +793,18 @@
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Postavke prozora povećala"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Dodirnite za otvaranje značajki pristupačnosti. Prilagodite ili zamijenite taj gumb u postavkama.\n\n"<annotation id="link">"Pregledajte postavke"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Pomaknite gumb do ruba da biste ga privremeno sakrili"</string>
+ <!-- no translation found for accessibility_floating_button_undo (511112888715708241) -->
+ <skip />
+ <!-- no translation found for accessibility_floating_button_undo_message_text (3044079592757099698) -->
+ <skip />
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Premjesti u gornji lijevi kut"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Premjesti u gornji desni kut"</string>
<string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Premjesti u donji lijevi kut"</string>
<string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Premjesti u donji desni kut"</string>
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Premjesti na rub i sakrij"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Ukloni s ruba i prikaži"</string>
+ <!-- no translation found for accessibility_floating_button_action_remove_menu (6730432848162552135) -->
+ <skip />
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"promijeni"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Kontrole uređaja"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Odabir aplikacije za dodavanje kontrola"</string>
@@ -933,6 +947,10 @@
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobilni podaci"</string>
<string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Povezano"</string>
+ <!-- no translation found for mobile_data_temp_connection_active (4590222725908806824) -->
+ <skip />
+ <!-- no translation found for mobile_data_poor_connection (819617772268371434) -->
+ <skip />
<string name="mobile_data_off_summary" msgid="3663995422004150567">"Mobilna veza neće se automatski uspostaviti"</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"Niste povezani"</string>
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"Nije dostupna nijedna druga mreža"</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 0f6daa2..cf07438 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -248,7 +248,8 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Fényerő"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Színek invertálása"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Színjavítás"</string>
- <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Felhasználói beállítások"</string>
+ <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) -->
+ <skip />
<string name="quick_settings_done" msgid="2163641301648855793">"Kész"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Bezárás"</string>
<string name="quick_settings_connected" msgid="3873605509184830379">"Csatlakoztatva"</string>
@@ -727,6 +728,14 @@
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Kikapcsolja a mobiladatokat?"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"Nem lesz adat-, illetve internet-hozzáférése a <xliff:g id="CARRIER">%s</xliff:g> szolgáltatón keresztül. Az internethez csak Wi-Fi-n keresztül csatlakozhat."</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"saját mobilszolgáltató"</string>
+ <!-- no translation found for auto_data_switch_disable_title (5146527155665190652) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_disable_message (5885533647399535852) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_negative_button (2370876875999891444) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_positive_button (8531782041263087564) -->
+ <skip />
<string name="touch_filtered_warning" msgid="8119511393338714836">"Mivel az egyik alkalmazás eltakarja az engedélykérést, a Beállítások alkalmazás nem tudja ellenőrizni az Ön válaszát."</string>
<string name="slice_permission_title" msgid="3262615140094151017">"Engedélyezi a(z) <xliff:g id="APP_0">%1$s</xliff:g> alkalmazásnak, hogy részleteket mutasson a(z) <xliff:g id="APP_2">%2$s</xliff:g> alkalmazásból?"</string>
<string name="slice_permission_text_1" msgid="6675965177075443714">"– Információkat olvashat a(z) <xliff:g id="APP">%1$s</xliff:g> alkalmazásból"</string>
@@ -785,12 +794,18 @@
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Nagyítóablak beállításai"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Koppintson a kisegítő lehetőségek megnyitásához. A gombot a Beállításokban módosíthatja.\n\n"<annotation id="link">"Beállítások"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"A gombot a szélre áthelyezve ideiglenesen elrejtheti"</string>
+ <!-- no translation found for accessibility_floating_button_undo (511112888715708241) -->
+ <skip />
+ <!-- no translation found for accessibility_floating_button_undo_message_text (3044079592757099698) -->
+ <skip />
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Áthelyezés fel és balra"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Áthelyezés fel és jobbra"</string>
<string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Áthelyezés le és balra"</string>
<string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Áthelyezés le és jobbra"</string>
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Áthelyezés a szélen kívül és elrejtés"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Áthelyezés a szélen kívül és mutatás"</string>
+ <!-- no translation found for accessibility_floating_button_action_remove_menu (6730432848162552135) -->
+ <skip />
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"váltás"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Eszközvezérlők"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Válasszon alkalmazást a vezérlők hozzáadásához"</string>
@@ -933,6 +948,10 @@
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobiladat"</string>
<string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="NETWORKMODE">%2$s</xliff:g>/<xliff:g id="STATE">%1$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Csatlakozva"</string>
+ <!-- no translation found for mobile_data_temp_connection_active (4590222725908806824) -->
+ <skip />
+ <!-- no translation found for mobile_data_poor_connection (819617772268371434) -->
+ <skip />
<string name="mobile_data_off_summary" msgid="3663995422004150567">"Nincs automatikus mobiladat-kapcsolat"</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"Nincs kapcsolat"</string>
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"Nincs több rendelkezésre álló hálózat"</string>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index 4724d5c..bfd051b 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -248,7 +248,8 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Պայծառություն"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Գունաշրջում"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Գունաշտկում"</string>
- <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Օգտատիրոջ կարգավորումներ"</string>
+ <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) -->
+ <skip />
<string name="quick_settings_done" msgid="2163641301648855793">"Պատրաստ է"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Փակել"</string>
<string name="quick_settings_connected" msgid="3873605509184830379">"Միացված է"</string>
@@ -727,6 +728,14 @@
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Անջատե՞լ բջջային ինտերնետը"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"<xliff:g id="CARRIER">%s</xliff:g> օպերատորի բջջային ինտերնետը հասանելի չի լինի: Համացանցից կկարողանաք օգտվել միայն Wi-Fi-ի միջոցով:"</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"Ձեր"</string>
+ <!-- no translation found for auto_data_switch_disable_title (5146527155665190652) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_disable_message (5885533647399535852) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_negative_button (2370876875999891444) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_positive_button (8531782041263087564) -->
+ <skip />
<string name="touch_filtered_warning" msgid="8119511393338714836">"Քանի որ ներածումն արգելափակված է ինչ-որ հավելվածի կողմից, Կարգավորումները չեն կարող հաստատել ձեր պատասխանը:"</string>
<string name="slice_permission_title" msgid="3262615140094151017">"Թույլատրե՞լ <xliff:g id="APP_0">%1$s</xliff:g> հավելվածին ցուցադրել հատվածներ <xliff:g id="APP_2">%2$s</xliff:g> հավելվածից"</string>
<string name="slice_permission_text_1" msgid="6675965177075443714">"- Կարող է կարդալ տեղեկություններ <xliff:g id="APP">%1$s</xliff:g> հավելվածից"</string>
@@ -785,12 +794,18 @@
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Խոշորացույցի պատուհանի կարգավորումներ"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Հատուկ գործառույթները բացելու համար հպեք։ Անհատականացրեք այս կոճակը կարգավորումներում։\n\n"<annotation id="link">"Կարգավորումներ"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Կոճակը ժամանակավորապես թաքցնելու համար այն տեղափոխեք էկրանի եզր"</string>
+ <!-- no translation found for accessibility_floating_button_undo (511112888715708241) -->
+ <skip />
+ <!-- no translation found for accessibility_floating_button_undo_message_text (3044079592757099698) -->
+ <skip />
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Տեղափոխել վերև՝ ձախ"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Տեղափոխել վերև՝ աջ"</string>
<string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Տեղափոխել ներքև՝ ձախ"</string>
<string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Տեղափոխել ներքև՝ աջ"</string>
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Տեղափոխել եզրից դուրս և թաքցնել"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Տեղափոխել եզրից դուրս և ցուցադրել"</string>
+ <!-- no translation found for accessibility_floating_button_action_remove_menu (6730432848162552135) -->
+ <skip />
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"միացնել/անջատել"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Սարքերի կառավարման տարրեր"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Ընտրեք հավելված` կառավարման տարրեր ավելացնելու համար"</string>
@@ -933,6 +948,10 @@
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Բջջային ինտերնետ"</string>
<string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Միացած է"</string>
+ <!-- no translation found for mobile_data_temp_connection_active (4590222725908806824) -->
+ <skip />
+ <!-- no translation found for mobile_data_poor_connection (819617772268371434) -->
+ <skip />
<string name="mobile_data_off_summary" msgid="3663995422004150567">"Բջջային ինտերնետն ավտոմատ չի միանա"</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"Կապ չկա"</string>
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"Այլ հասանելի ցանցեր չկան"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 8fefe40..87496cf 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -248,7 +248,8 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Kecerahan"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Inversi warna"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Koreksi warna"</string>
- <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Setelan pengguna"</string>
+ <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) -->
+ <skip />
<string name="quick_settings_done" msgid="2163641301648855793">"Selesai"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Tutup"</string>
<string name="quick_settings_connected" msgid="3873605509184830379">"Terhubung"</string>
@@ -727,6 +728,14 @@
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Nonaktifkan data seluler?"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"Anda tidak akan dapat mengakses data atau internet melalui <xliff:g id="CARRIER">%s</xliff:g>. Internet hanya akan tersedia melalui Wi-Fi."</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"Operator Seluler Anda"</string>
+ <!-- no translation found for auto_data_switch_disable_title (5146527155665190652) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_disable_message (5885533647399535852) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_negative_button (2370876875999891444) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_positive_button (8531782041263087564) -->
+ <skip />
<string name="touch_filtered_warning" msgid="8119511393338714836">"Karena sebuah aplikasi menghalangi permintaan izin, Setelan tidak dapat memverifikasi respons Anda."</string>
<string name="slice_permission_title" msgid="3262615140094151017">"Izinkan <xliff:g id="APP_0">%1$s</xliff:g> menampilkan potongan <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
<string name="slice_permission_text_1" msgid="6675965177075443714">"- Dapat membaca informasi dari <xliff:g id="APP">%1$s</xliff:g>"</string>
@@ -785,12 +794,18 @@
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Setelan jendela kaca pembesar"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Ketuk untuk membuka fitur aksesibilitas. Sesuaikan atau ganti tombol ini di Setelan.\n\n"<annotation id="link">"Lihat setelan"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Pindahkan tombol ke tepi agar tersembunyi untuk sementara"</string>
+ <!-- no translation found for accessibility_floating_button_undo (511112888715708241) -->
+ <skip />
+ <!-- no translation found for accessibility_floating_button_undo_message_text (3044079592757099698) -->
+ <skip />
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Pindahkan ke kiri atas"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Pindahkan ke kanan atas"</string>
<string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Pindahkan ke kiri bawah"</string>
<string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Pindahkan ke kanan bawah"</string>
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Pindahkan ke tepi dan sembunyikan"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Pindahkan dari tepi dan tampilkan"</string>
+ <!-- no translation found for accessibility_floating_button_action_remove_menu (6730432848162552135) -->
+ <skip />
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"alihkan"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Kontrol perangkat"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Pilih aplikasi untuk menambahkan kontrol"</string>
@@ -933,6 +948,10 @@
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Data seluler"</string>
<string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Terhubung"</string>
+ <!-- no translation found for mobile_data_temp_connection_active (4590222725908806824) -->
+ <skip />
+ <!-- no translation found for mobile_data_poor_connection (819617772268371434) -->
+ <skip />
<string name="mobile_data_off_summary" msgid="3663995422004150567">"Data seluler tidak akan terhubung otomatis"</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"Tidak ada koneksi"</string>
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"Jaringan lain tidak tersedia"</string>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index d22680e..3d7e2ea 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -248,7 +248,8 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Birtustig"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Umsnúningur lita"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Litaleiðrétting"</string>
- <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Notandastillingar"</string>
+ <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) -->
+ <skip />
<string name="quick_settings_done" msgid="2163641301648855793">"Lokið"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Loka"</string>
<string name="quick_settings_connected" msgid="3873605509184830379">"Tengt"</string>
@@ -727,6 +728,14 @@
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Viltu slökkva á farsímagögnum?"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"Þú munt ekki hafa aðgang að gögnum eða internetinu í gegnum <xliff:g id="CARRIER">%s</xliff:g>. Aðeins verður hægt að tengjast internetinu með Wi-Fi."</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"símafyrirtækið þitt"</string>
+ <!-- no translation found for auto_data_switch_disable_title (5146527155665190652) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_disable_message (5885533647399535852) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_negative_button (2370876875999891444) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_positive_button (8531782041263087564) -->
+ <skip />
<string name="touch_filtered_warning" msgid="8119511393338714836">"Stillingar geta ekki staðfest svarið þitt vegna þess að forrit er að fela heimildarbeiðni."</string>
<string name="slice_permission_title" msgid="3262615140094151017">"Viltu leyfa <xliff:g id="APP_0">%1$s</xliff:g> að sýna sneiðar úr <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
<string name="slice_permission_text_1" msgid="6675965177075443714">"- Það getur lesið upplýsingar úr <xliff:g id="APP">%1$s</xliff:g>"</string>
@@ -785,12 +794,18 @@
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Stillingar stækkunarglugga"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Ýttu til að opna aðgengiseiginleika. Sérsníddu eða skiptu hnappinum út í stillingum.\n\n"<annotation id="link">"Skoða stillingar"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Færðu hnappinn að brúninni til að fela hann tímabundið"</string>
+ <!-- no translation found for accessibility_floating_button_undo (511112888715708241) -->
+ <skip />
+ <!-- no translation found for accessibility_floating_button_undo_message_text (3044079592757099698) -->
+ <skip />
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Færa efst til vinstri"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Færa efst til hægri"</string>
<string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Færa neðst til vinstri"</string>
<string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Færa neðst til hægri"</string>
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Færa að jaðri og fela"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Færa að jaðri og birta"</string>
+ <!-- no translation found for accessibility_floating_button_action_remove_menu (6730432848162552135) -->
+ <skip />
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"kveikja/slökkva"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Tækjastjórnun"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Veldu forrit til að bæta við stýringum"</string>
@@ -933,6 +948,10 @@
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Farsímagögn"</string>
<string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Tengt"</string>
+ <!-- no translation found for mobile_data_temp_connection_active (4590222725908806824) -->
+ <skip />
+ <!-- no translation found for mobile_data_poor_connection (819617772268371434) -->
+ <skip />
<string name="mobile_data_off_summary" msgid="3663995422004150567">"Farsímagögn tengjast ekki sjálfkrafa"</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"Engin tenging"</string>
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"Engin önnur net í boði"</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index df6c14f..1115680 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -248,7 +248,8 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Luminosità"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Inversione dei colori"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Correzione del colore"</string>
- <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Impostazioni utente"</string>
+ <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) -->
+ <skip />
<string name="quick_settings_done" msgid="2163641301648855793">"Fine"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Chiudi"</string>
<string name="quick_settings_connected" msgid="3873605509184830379">"Connesso"</string>
@@ -727,6 +728,14 @@
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Disattivare i dati mobili?"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"Non avrai accesso ai dati o a Internet tramite <xliff:g id="CARRIER">%s</xliff:g>. Internet sarà disponibile soltanto tramite Wi-Fi."</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"il tuo operatore"</string>
+ <!-- no translation found for auto_data_switch_disable_title (5146527155665190652) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_disable_message (5885533647399535852) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_negative_button (2370876875999891444) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_positive_button (8531782041263087564) -->
+ <skip />
<string name="touch_filtered_warning" msgid="8119511393338714836">"Un\'app sta oscurando una richiesta di autorizzazione, pertanto Impostazioni non può verificare la tua risposta."</string>
<string name="slice_permission_title" msgid="3262615140094151017">"Vuoi consentire all\'app <xliff:g id="APP_0">%1$s</xliff:g> di mostrare porzioni dell\'app <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
<string name="slice_permission_text_1" msgid="6675965177075443714">"- Può leggere informazioni dell\'app <xliff:g id="APP">%1$s</xliff:g>"</string>
@@ -785,12 +794,18 @@
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Impostazioni della finestra di ingrandimento"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Tocca per aprire funzioni di accessibilità. Personalizza o sostituisci il pulsante in Impostazioni.\n\n"<annotation id="link">"Vedi impostazioni"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Sposta il pulsante fino al bordo per nasconderlo temporaneamente"</string>
+ <!-- no translation found for accessibility_floating_button_undo (511112888715708241) -->
+ <skip />
+ <!-- no translation found for accessibility_floating_button_undo_message_text (3044079592757099698) -->
+ <skip />
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Sposta in alto a sinistra"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Sposta in alto a destra"</string>
<string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Sposta in basso a sinistra"</string>
<string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Sposta in basso a destra"</string>
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Sposta fino a bordo e nascondi"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Sposta fuori da bordo e mostra"</string>
+ <!-- no translation found for accessibility_floating_button_action_remove_menu (6730432848162552135) -->
+ <skip />
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"attiva/disattiva"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Controllo dispositivi"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Scegli un\'app per aggiungere controlli"</string>
@@ -933,6 +948,10 @@
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Dati mobili"</string>
<string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Connessione attiva"</string>
+ <!-- no translation found for mobile_data_temp_connection_active (4590222725908806824) -->
+ <skip />
+ <!-- no translation found for mobile_data_poor_connection (819617772268371434) -->
+ <skip />
<string name="mobile_data_off_summary" msgid="3663995422004150567">"Nessuna connessione dati mobili automatica"</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"Nessuna connessione"</string>
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"Nessun\'altra rete disponibile"</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index f24964a..1fe4e3e 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -248,7 +248,7 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"בהירות"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"היפוך צבעים"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"תיקון צבע"</string>
- <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"הגדרות המשתמש"</string>
+ <string name="quick_settings_more_user_settings" msgid="7634653308485206306">"ניהול משתמשים"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"סיום"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"סגירה"</string>
<string name="quick_settings_connected" msgid="3873605509184830379">"מחובר"</string>
@@ -727,6 +727,14 @@
<string name="mobile_data_disable_title" msgid="5366476131671617790">"לכבות את חבילת הגלישה?"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"לא תהיה לך גישה לנתונים או לאינטרנט באמצעות <xliff:g id="CARRIER">%s</xliff:g>. אינטרנט יהיה זמין רק באמצעות Wi-Fi."</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"הספק שלך"</string>
+ <!-- no translation found for auto_data_switch_disable_title (5146527155665190652) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_disable_message (5885533647399535852) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_negative_button (2370876875999891444) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_positive_button (8531782041263087564) -->
+ <skip />
<string name="touch_filtered_warning" msgid="8119511393338714836">"יש אפליקציה שמסתירה את בקשת ההרשאה, ולכן אין אפשרות לאמת את התשובה בהגדרות."</string>
<string name="slice_permission_title" msgid="3262615140094151017">"האם לאפשר ל-<xliff:g id="APP_0">%1$s</xliff:g> להציג חלקים מ-<xliff:g id="APP_2">%2$s</xliff:g>?"</string>
<string name="slice_permission_text_1" msgid="6675965177075443714">"- תהיה לה אפשרות לקרוא מידע מאפליקציית <xliff:g id="APP">%1$s</xliff:g>"</string>
@@ -785,12 +793,18 @@
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"ההגדרות של חלון ההגדלה"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"מקישים כדי לפתוח את תכונות הנגישות. אפשר להחליף את הלחצן או להתאים אותו אישית בהגדרות.\n\n"<annotation id="link">"הצגת ההגדרות"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"כדי להסתיר זמנית את הלחצן, יש להזיז אותו לקצה"</string>
+ <!-- no translation found for accessibility_floating_button_undo (511112888715708241) -->
+ <skip />
+ <!-- no translation found for accessibility_floating_button_undo_message_text (3044079592757099698) -->
+ <skip />
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"העברה לפינה השמאלית העליונה"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"העברה לפינה הימנית העליונה"</string>
<string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"העברה לפינה השמאלית התחתונה"</string>
<string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"העברה לפינה הימנית התחתונה"</string>
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"העברה לשוליים והסתרה"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"העברה מהשוליים והצגה"</string>
+ <!-- no translation found for accessibility_floating_button_action_remove_menu (6730432848162552135) -->
+ <skip />
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"החלפת מצב"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"פקדי מכשירים"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"יש לבחור אפליקציה כדי להוסיף פקדים"</string>
@@ -933,6 +947,10 @@
<string name="mobile_data_settings_title" msgid="3955246641380064901">"חבילת גלישה"</string>
<string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"מחובר"</string>
+ <!-- no translation found for mobile_data_temp_connection_active (4590222725908806824) -->
+ <skip />
+ <!-- no translation found for mobile_data_poor_connection (819617772268371434) -->
+ <skip />
<string name="mobile_data_off_summary" msgid="3663995422004150567">"החיבור לנתונים סלולריים לא מתבצע באופן אוטומטי"</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"אין חיבור"</string>
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"אין רשתות זמינות אחרות"</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 7ea7223..b00ceb4 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -248,7 +248,8 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"画面の明るさ"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"色反転"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"色補正"</string>
- <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"ユーザー設定"</string>
+ <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) -->
+ <skip />
<string name="quick_settings_done" msgid="2163641301648855793">"完了"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"閉じる"</string>
<string name="quick_settings_connected" msgid="3873605509184830379">"接続済み"</string>
@@ -727,6 +728,14 @@
<string name="mobile_data_disable_title" msgid="5366476131671617790">"モバイルデータを OFF にしますか?"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"<xliff:g id="CARRIER">%s</xliff:g>でデータやインターネットにアクセスできなくなります。インターネットには Wi-Fi からのみ接続できます。"</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"携帯通信会社"</string>
+ <!-- no translation found for auto_data_switch_disable_title (5146527155665190652) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_disable_message (5885533647399535852) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_negative_button (2370876875999891444) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_positive_button (8531782041263087564) -->
+ <skip />
<string name="touch_filtered_warning" msgid="8119511393338714836">"アプリが許可リクエストを隠しているため、設定側でユーザーの応答を確認できません。"</string>
<string name="slice_permission_title" msgid="3262615140094151017">"「<xliff:g id="APP_2">%2$s</xliff:g>」のスライスの表示を「<xliff:g id="APP_0">%1$s</xliff:g>」に許可しますか?"</string>
<string name="slice_permission_text_1" msgid="6675965177075443714">"- 「<xliff:g id="APP">%1$s</xliff:g>」からの情報の読み取り"</string>
@@ -785,12 +794,18 @@
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"拡大鏡ウィンドウの設定"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"タップしてユーザー補助機能を開きます。ボタンのカスタマイズや入れ替えを [設定] で行えます。\n\n"<annotation id="link">"設定を表示"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"ボタンを一時的に非表示にするには、端に移動させてください"</string>
+ <!-- no translation found for accessibility_floating_button_undo (511112888715708241) -->
+ <skip />
+ <!-- no translation found for accessibility_floating_button_undo_message_text (3044079592757099698) -->
+ <skip />
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"左上に移動"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"右上に移動"</string>
<string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"左下に移動"</string>
<string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"右下に移動"</string>
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"端に移動して非表示"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"端から移動して表示"</string>
+ <!-- no translation found for accessibility_floating_button_action_remove_menu (6730432848162552135) -->
+ <skip />
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"切り替え"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"デバイス コントロール"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"コントロールを追加するアプリの選択"</string>
@@ -933,6 +948,10 @@
<string name="mobile_data_settings_title" msgid="3955246641380064901">"モバイルデータ"</string>
<string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"接続済み"</string>
+ <!-- no translation found for mobile_data_temp_connection_active (4590222725908806824) -->
+ <skip />
+ <!-- no translation found for mobile_data_poor_connection (819617772268371434) -->
+ <skip />
<string name="mobile_data_off_summary" msgid="3663995422004150567">"モバイルデータには自動接続しません"</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"接続なし"</string>
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"利用できるネットワークはありません"</string>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index 93c9d94..aab9a32 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -248,7 +248,8 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"განათება"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"ფერთა ინვერსია"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"ფერთა კორექცია"</string>
- <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"მომხმარებლის პარამეტრები"</string>
+ <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) -->
+ <skip />
<string name="quick_settings_done" msgid="2163641301648855793">"დასრულდა"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"დახურვა"</string>
<string name="quick_settings_connected" msgid="3873605509184830379">"დაკავშირებულია"</string>
@@ -727,6 +728,14 @@
<string name="mobile_data_disable_title" msgid="5366476131671617790">"გსურთ მობილური ინტერნეტის გამორთვა?"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"თქვენ არ გექნებათ მობილურ ინტერნეტზე ან ზოგადად ინტერნეტზე წვდომა <xliff:g id="CARRIER">%s</xliff:g>-ის მეშვეობით. ინტერნეტი მხოლოდ Wi-Fi-კავშირის მეშვეობით იქნება ხელმისაწვდომი."</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"თქვენი ოპერატორი"</string>
+ <!-- no translation found for auto_data_switch_disable_title (5146527155665190652) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_disable_message (5885533647399535852) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_negative_button (2370876875999891444) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_positive_button (8531782041263087564) -->
+ <skip />
<string name="touch_filtered_warning" msgid="8119511393338714836">"ვინაიდან აპი ფარავს ნებართვის მოთხოვნას, პარამეტრების მიერ თქვენი პასუხი ვერ დასტურდება."</string>
<string name="slice_permission_title" msgid="3262615140094151017">"ანიჭებთ ნებართვას <xliff:g id="APP_0">%1$s</xliff:g>-ს, აჩვენოს <xliff:g id="APP_2">%2$s</xliff:g>-ის ფრაგმენტები?"</string>
<string name="slice_permission_text_1" msgid="6675965177075443714">"- მას შეუძლია ინფორმაციის <xliff:g id="APP">%1$s</xliff:g>-დან წაკითხვა"</string>
@@ -785,12 +794,18 @@
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"გადიდების ფანჯრის პარამეტრები"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"შეეხეთ მარტივი წვდომის ფუნქციების გასახსნელად. მოარგეთ ან შეცვალეთ ეს ღილაკი პარამეტრებში.\n\n"<annotation id="link">"პარამეტრების ნახვა"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"გადაიტანეთ ღილაკი კიდეში, რათა დროებით დამალოთ ის"</string>
+ <!-- no translation found for accessibility_floating_button_undo (511112888715708241) -->
+ <skip />
+ <!-- no translation found for accessibility_floating_button_undo_message_text (3044079592757099698) -->
+ <skip />
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"ზევით და მარცხნივ გადატანა"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"ზევით და მარჯვნივ გადატანა"</string>
<string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"ქვევით და მარცხნივ გადატანა"</string>
<string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"ქვემოთ და მარჯვნივ გადატანა"</string>
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"კიდეში გადატანა და დამალვა"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"კიდეში გადატანა და გამოჩენა"</string>
+ <!-- no translation found for accessibility_floating_button_action_remove_menu (6730432848162552135) -->
+ <skip />
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"გადართვა"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"მოწყობილ. მართვის საშუალებები"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"აირჩიეთ აპი მართვის საშუალებების დასამატებლად"</string>
@@ -933,6 +948,10 @@
<string name="mobile_data_settings_title" msgid="3955246641380064901">"მობილური ინტერნეტი"</string>
<string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"დაკავშირებული"</string>
+ <!-- no translation found for mobile_data_temp_connection_active (4590222725908806824) -->
+ <skip />
+ <!-- no translation found for mobile_data_poor_connection (819617772268371434) -->
+ <skip />
<string name="mobile_data_off_summary" msgid="3663995422004150567">"მობილურ ინტერნეტს ავტომატურად არ დაუკავშირდება"</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"კავშირი არ არის"</string>
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"სხვა ქსელები მიუწვდომელია"</string>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index e096b7e..19bfdf5 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -248,7 +248,8 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Жарықтығы"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Түс инверсиясы"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Түсті түзету"</string>
- <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Пайдаланушы параметрлері"</string>
+ <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) -->
+ <skip />
<string name="quick_settings_done" msgid="2163641301648855793">"Дайын"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Жабу"</string>
<string name="quick_settings_connected" msgid="3873605509184830379">"Қосылды"</string>
@@ -727,6 +728,14 @@
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Мобильдік интернет өшірілсін бе?"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"<xliff:g id="CARRIER">%s</xliff:g> операторы арқылы деректерге немесе интернетке кіре алмайсыз. Интернетке тек Wi-Fi арқылы кіресіз."</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"операторыңыз"</string>
+ <!-- no translation found for auto_data_switch_disable_title (5146527155665190652) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_disable_message (5885533647399535852) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_negative_button (2370876875999891444) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_positive_button (8531782041263087564) -->
+ <skip />
<string name="touch_filtered_warning" msgid="8119511393338714836">"Басқа қолданба рұқсат сұрауын жасырып тұрғандықтан, параметрлер жауабыңызды растай алмайды."</string>
<string name="slice_permission_title" msgid="3262615140094151017">"<xliff:g id="APP_0">%1$s</xliff:g> қолданбасына <xliff:g id="APP_2">%2$s</xliff:g> қолданбасының үзінділерін көрсетуге рұқсат берілсін бе?"</string>
<string name="slice_permission_text_1" msgid="6675965177075443714">"- Бұл <xliff:g id="APP">%1$s</xliff:g> қолданбасындағы ақпаратты оқи алады"</string>
@@ -785,12 +794,18 @@
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Ұлғайтқыш терезесінің параметрлері"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Арнайы мүмкіндікті ашу үшін түртіңіз. Түймені параметрден реттеңіз не ауыстырыңыз.\n\n"<annotation id="link">"Параметрді көру"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Түймені уақытша жасыру үшін оны шетке қарай жылжытыңыз."</string>
+ <!-- no translation found for accessibility_floating_button_undo (511112888715708241) -->
+ <skip />
+ <!-- no translation found for accessibility_floating_button_undo_message_text (3044079592757099698) -->
+ <skip />
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Жоғарғы сол жаққа жылжыту"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Жоғарғы оң жаққа жылжыту"</string>
<string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Төменгі сол жаққа жылжыту"</string>
<string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Төменгі оң жаққа жылжыту"</string>
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Шетке жылжыту және жасыру"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Шетке жылжыту және көрсету"</string>
+ <!-- no translation found for accessibility_floating_button_action_remove_menu (6730432848162552135) -->
+ <skip />
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"ауыстыру"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Құрылғыны басқару элементтері"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Басқару элементтері қосылатын қолданбаны таңдаңыз"</string>
@@ -933,6 +948,10 @@
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Мобильдік интернет"</string>
<string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Жалғанды"</string>
+ <!-- no translation found for mobile_data_temp_connection_active (4590222725908806824) -->
+ <skip />
+ <!-- no translation found for mobile_data_poor_connection (819617772268371434) -->
+ <skip />
<string name="mobile_data_off_summary" msgid="3663995422004150567">"Мобильдік интернет автоматты түрде қосылмайды."</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"Байланыс жоқ"</string>
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"Басқа қолжетімді желі жоқ"</string>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index aa641e4..186244b 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -248,7 +248,8 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"ពន្លឺ"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"ការបញ្ច្រាសពណ៌"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"ការកែតម្រូវពណ៌"</string>
- <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"ការកំណត់អ្នកប្រើប្រាស់"</string>
+ <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) -->
+ <skip />
<string name="quick_settings_done" msgid="2163641301648855793">"រួចរាល់"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"បិទ"</string>
<string name="quick_settings_connected" msgid="3873605509184830379">"បានភ្ជាប់"</string>
@@ -727,6 +728,14 @@
<string name="mobile_data_disable_title" msgid="5366476131671617790">"បិទទិន្នន័យទូរសព្ទចល័ត?"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"អ្នកនឹងមិនមានសិទ្ធិចូលប្រើទិន្នន័យ ឬអ៊ីនធឺណិតតាមរយៈ <xliff:g id="CARRIER">%s</xliff:g> បានឡើយ។ អ៊ីនធឺណិតនឹងអាចប្រើបានតាមរយៈ Wi-Fi តែប៉ុណ្ណោះ។"</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"ក្រុមហ៊ុនសេវាទូរសព្ទរបស់អ្នក"</string>
+ <!-- no translation found for auto_data_switch_disable_title (5146527155665190652) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_disable_message (5885533647399535852) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_negative_button (2370876875999891444) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_positive_button (8531782041263087564) -->
+ <skip />
<string name="touch_filtered_warning" msgid="8119511393338714836">"ការកំណត់មិនអាចផ្ទៀងផ្ទាត់ការឆ្លើយតបរបស់អ្នកបានទេ ដោយសារកម្មវិធីកំពុងបាំងសំណើសុំការអនុញ្ញាត។"</string>
<string name="slice_permission_title" msgid="3262615140094151017">"អនុញ្ញាតឱ្យ <xliff:g id="APP_0">%1$s</xliff:g> បង្ហាញស្ថិតិប្រើប្រាស់របស់ <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
<string name="slice_permission_text_1" msgid="6675965177075443714">"- វាអាចអានព័ត៌មានពី <xliff:g id="APP">%1$s</xliff:g>"</string>
@@ -785,12 +794,18 @@
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"ការកំណត់វិនដូកម្មវិធីពង្រីក"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"ចុចដើម្បីបើកមុខងារភាពងាយស្រួល។ ប្ដូរ ឬប្ដូរប៊ូតុងនេះតាមបំណងនៅក្នុងការកំណត់។\n\n"<annotation id="link">"មើលការកំណត់"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"ផ្លាស់ទីប៊ូតុងទៅគែម ដើម្បីលាក់វាជាបណ្ដោះអាសន្ន"</string>
+ <!-- no translation found for accessibility_floating_button_undo (511112888715708241) -->
+ <skip />
+ <!-- no translation found for accessibility_floating_button_undo_message_text (3044079592757099698) -->
+ <skip />
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"ផ្លាស់ទីទៅខាងលើផ្នែកខាងឆ្វេង"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"ផ្លាស់ទីទៅខាងលើផ្នែកខាងស្ដាំ"</string>
<string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"ផ្លាស់ទីទៅខាងក្រោមផ្នែកខាងឆ្វេង"</string>
<string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"ផ្លាស់ទីទៅខាងក្រោមផ្នែកខាងស្ដាំ"</string>
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"ផ្លាស់ទីទៅផ្នែកខាងចុង រួចលាក់"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"ផ្លាស់ទីចេញពីផ្នែកខាងចុង រួចបង្ហាញ"</string>
+ <!-- no translation found for accessibility_floating_button_action_remove_menu (6730432848162552135) -->
+ <skip />
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"បិទ/បើក"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"ផ្ទាំងគ្រប់គ្រងឧបករណ៍"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"ជ្រើសរើសកម្មវិធីដែលត្រូវបញ្ចូលផ្ទាំងគ្រប់គ្រង"</string>
@@ -933,6 +948,10 @@
<string name="mobile_data_settings_title" msgid="3955246641380064901">"ទិន្នន័យទូរសព្ទចល័ត"</string>
<string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"បានភ្ជាប់"</string>
+ <!-- no translation found for mobile_data_temp_connection_active (4590222725908806824) -->
+ <skip />
+ <!-- no translation found for mobile_data_poor_connection (819617772268371434) -->
+ <skip />
<string name="mobile_data_off_summary" msgid="3663995422004150567">"ទិន្នន័យទូរសព្ទចល័តនឹងមិនភ្ជាប់ដោយស្វ័យប្រវត្តិទេ"</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"មិនមានការតភ្ជាប់ទេ"</string>
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"មិនមានបណ្ដាញផ្សេងទៀតដែលអាចប្រើបានទេ"</string>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index ab3f379..3341f8d 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -248,7 +248,8 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"ಪ್ರಕಾಶಮಾನ"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"ಕಲರ್ ಇನ್ವರ್ಶನ್"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"ಬಣ್ಣದ ತಿದ್ದುಪಡಿ"</string>
- <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"ಬಳಕೆದಾರರ ಸೆಟ್ಟಿಂಗ್ಗಳು"</string>
+ <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) -->
+ <skip />
<string name="quick_settings_done" msgid="2163641301648855793">"ಮುಗಿದಿದೆ"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"ಮುಚ್ಚಿರಿ"</string>
<string name="quick_settings_connected" msgid="3873605509184830379">"ಸಂಪರ್ಕಗೊಂಡಿದೆ"</string>
@@ -727,6 +728,14 @@
<string name="mobile_data_disable_title" msgid="5366476131671617790">"ಮೊಬೈಲ್ ಡೇಟಾ ಆಫ್ ಮಾಡಬೇಕೆ?"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"ನೀವು <xliff:g id="CARRIER">%s</xliff:g> ಮೂಲಕ ಡೇಟಾ ಅಥವಾ ಇಂಟರ್ನೆಟ್ಗೆ ಪ್ರವೇಶವನ್ನು ಹೊಂದಿರುವುದಿಲ್ಲ. ಇಂಟರ್ನೆಟ್, ವೈ-ಫೈ ಮೂಲಕ ಮಾತ್ರ ಲಭ್ಯವಿರುತ್ತದೆ."</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"ನಿಮ್ಮ ವಾಹಕ"</string>
+ <!-- no translation found for auto_data_switch_disable_title (5146527155665190652) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_disable_message (5885533647399535852) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_negative_button (2370876875999891444) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_positive_button (8531782041263087564) -->
+ <skip />
<string name="touch_filtered_warning" msgid="8119511393338714836">"ಅನುಮತಿ ವಿನಂತಿಯನ್ನು ಅಪ್ಲಿಕೇಶನ್ ಮರೆಮಾಚುತ್ತಿರುವ ಕಾರಣ, ಸೆಟ್ಟಿಂಗ್ಗಳಿಗೆ ನಿಮ್ಮ ಪ್ರತಿಕ್ರಿಯೆಯನ್ನು ಪರಿಶೀಲಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ."</string>
<string name="slice_permission_title" msgid="3262615140094151017">"<xliff:g id="APP_2">%2$s</xliff:g> ಸ್ಲೈಸ್ಗಳನ್ನು ತೋರಿಸಲು <xliff:g id="APP_0">%1$s</xliff:g> ಅನ್ನು ಅನುಮತಿಸುವುದೇ?"</string>
<string name="slice_permission_text_1" msgid="6675965177075443714">"- ಇದು <xliff:g id="APP">%1$s</xliff:g> ನಿಂದ ಮಾಹಿತಿಯನ್ನು ಓದಬಹುದು"</string>
@@ -785,12 +794,18 @@
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"ಮ್ಯಾಗ್ನಿಫೈರ್ ವಿಂಡೋ ಸೆಟ್ಟಿಂಗ್ಗಳು"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"ಪ್ರವೇಶಿಸುವಿಕೆ ವೈಶಿಷ್ಟ್ಯಗಳನ್ನು ತೆರೆಯಲು ಟ್ಯಾಪ್ ಮಾಡಿ. ಸೆಟ್ಟಿಂಗ್ಗಳಲ್ಲಿ ಈ ಬಟನ್ ಅನ್ನು ಕಸ್ಟಮೈಸ್ ಮಾಡಿ ಅಥವಾ ಬದಲಾಯಿಸಿ.\n\n"<annotation id="link">"ಸೆಟ್ಟಿಂಗ್ಗಳನ್ನು ವೀಕ್ಷಿಸಿ"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"ಅದನ್ನು ತಾತ್ಕಾಲಿಕವಾಗಿ ಮರೆಮಾಡಲು ಅಂಚಿಗೆ ಬಟನ್ ಸರಿಸಿ"</string>
+ <!-- no translation found for accessibility_floating_button_undo (511112888715708241) -->
+ <skip />
+ <!-- no translation found for accessibility_floating_button_undo_message_text (3044079592757099698) -->
+ <skip />
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"ಎಡ ಮೇಲ್ಭಾಗಕ್ಕೆ ಸರಿಸಿ"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"ಬಲ ಮೇಲ್ಭಾಗಕ್ಕೆ ಸರಿಸಿ"</string>
<string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"ಸ್ಕ್ರೀನ್ನ ಎಡ ಕೆಳಭಾಗಕ್ಕೆ ಸರಿಸಿ"</string>
<string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"ಕೆಳಗಿನ ಬಲಭಾಗಕ್ಕೆ ಸರಿಸಿ"</string>
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"ಅಂಚಿಗೆ ಸರಿಸಿ ಮತ್ತು ಮರೆಮಾಡಿ"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"ಅಂಚನ್ನು ಸರಿಸಿ ಮತ್ತು ತೋರಿಸಿ"</string>
+ <!-- no translation found for accessibility_floating_button_action_remove_menu (6730432848162552135) -->
+ <skip />
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"ಟಾಗಲ್ ಮಾಡಿ"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"ಸಾಧನ ನಿಯಂತ್ರಣಗಳು"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"ನಿಯಂತ್ರಣಗಳನ್ನು ಸೇರಿಸಲು ಆ್ಯಪ್ ಅನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string>
@@ -933,6 +948,10 @@
<string name="mobile_data_settings_title" msgid="3955246641380064901">"ಮೊಬೈಲ್ ಡೇಟಾ"</string>
<string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"ಕನೆಕ್ಟ್ ಆಗಿದೆ"</string>
+ <!-- no translation found for mobile_data_temp_connection_active (4590222725908806824) -->
+ <skip />
+ <!-- no translation found for mobile_data_poor_connection (819617772268371434) -->
+ <skip />
<string name="mobile_data_off_summary" msgid="3663995422004150567">"ಮೊಬೈಲ್ ಡೇಟಾ ಸ್ವಯಂಚಾಲಿತವಾಗಿ ಕನೆಕ್ಟ್ ಆಗುವುದಿಲ್ಲ"</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"ಯಾವುದೇ ಕನೆಕ್ಷನ್ ಇಲ್ಲ"</string>
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"ಇತರ ಯಾವುದೇ ನೆಟ್ವರ್ಕ್ಗಳು ಲಭ್ಯವಿಲ್ಲ"</string>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 11da089..783365c 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -248,7 +248,8 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"밝기"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"색상 반전"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"색상 보정"</string>
- <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"사용자 설정"</string>
+ <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) -->
+ <skip />
<string name="quick_settings_done" msgid="2163641301648855793">"완료"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"닫기"</string>
<string name="quick_settings_connected" msgid="3873605509184830379">"연결됨"</string>
@@ -727,6 +728,14 @@
<string name="mobile_data_disable_title" msgid="5366476131671617790">"모바일 데이터를 사용 중지하시겠습니까?"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"<xliff:g id="CARRIER">%s</xliff:g>을(를) 통해 데이터 또는 인터넷에 액세스할 수 없게 됩니다. 인터넷은 Wi-Fi를 통해서만 사용할 수 있습니다."</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"이동통신사"</string>
+ <!-- no translation found for auto_data_switch_disable_title (5146527155665190652) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_disable_message (5885533647399535852) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_negative_button (2370876875999891444) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_positive_button (8531782041263087564) -->
+ <skip />
<string name="touch_filtered_warning" msgid="8119511393338714836">"앱이 권한 요청을 가리고 있기 때문에 설정에서 내 응답을 확인할 수 없습니다."</string>
<string name="slice_permission_title" msgid="3262615140094151017">"<xliff:g id="APP_0">%1$s</xliff:g>에서 <xliff:g id="APP_2">%2$s</xliff:g>의 슬라이스를 표시하도록 허용하시겠습니까?"</string>
<string name="slice_permission_text_1" msgid="6675965177075443714">"- <xliff:g id="APP">%1$s</xliff:g>의 정보를 읽을 수 있음"</string>
@@ -785,12 +794,18 @@
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"돋보기 창 설정"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"접근성 기능을 열려면 탭하세요. 설정에서 이 버튼을 맞춤설정하거나 교체할 수 있습니다.\n\n"<annotation id="link">"설정 보기"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"버튼을 가장자리로 옮겨서 일시적으로 숨기세요."</string>
+ <!-- no translation found for accessibility_floating_button_undo (511112888715708241) -->
+ <skip />
+ <!-- no translation found for accessibility_floating_button_undo_message_text (3044079592757099698) -->
+ <skip />
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"왼쪽 상단으로 이동"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"오른쪽 상단으로 이동"</string>
<string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"왼쪽 하단으로 이동"</string>
<string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"오른쪽 하단으로 이동"</string>
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"가장자리로 옮겨서 숨기기"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"가장자리 바깥으로 옮겨서 표시"</string>
+ <!-- no translation found for accessibility_floating_button_action_remove_menu (6730432848162552135) -->
+ <skip />
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"전환"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"기기 컨트롤"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"컨트롤을 추가할 앱을 선택하세요"</string>
@@ -933,6 +948,10 @@
<string name="mobile_data_settings_title" msgid="3955246641380064901">"모바일 데이터"</string>
<string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"연결됨"</string>
+ <!-- no translation found for mobile_data_temp_connection_active (4590222725908806824) -->
+ <skip />
+ <!-- no translation found for mobile_data_poor_connection (819617772268371434) -->
+ <skip />
<string name="mobile_data_off_summary" msgid="3663995422004150567">"모바일 데이터가 자동으로 연결되지 않음"</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"연결되지 않음"</string>
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"사용 가능한 다른 네트워크가 없음"</string>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index 676076c..b9da9f0 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -248,7 +248,8 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Жарыктыгы"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Түстөрдү инверсиялоо"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Түстөрдү тууралоо"</string>
- <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Колдонуучунун параметрлери"</string>
+ <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) -->
+ <skip />
<string name="quick_settings_done" msgid="2163641301648855793">"Бүттү"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Жабуу"</string>
<string name="quick_settings_connected" msgid="3873605509184830379">"Туташкан"</string>
@@ -727,6 +728,14 @@
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Мобилдик Интернетти өчүрөсүзбү?"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"<xliff:g id="CARRIER">%s</xliff:g> байланыш оператору аркылуу Интернетке кире албай каласыз. Интернетке Wi-Fi аркылуу гана кирүүгө болот."</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"байланыш операторуңуз"</string>
+ <!-- no translation found for auto_data_switch_disable_title (5146527155665190652) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_disable_message (5885533647399535852) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_negative_button (2370876875999891444) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_positive_button (8531782041263087564) -->
+ <skip />
<string name="touch_filtered_warning" msgid="8119511393338714836">"Уруксат берүү сурамыңыз көрүнбөй калгандыктан, Жөндөөлөр жообуңузду ырастай албай жатат."</string>
<string name="slice_permission_title" msgid="3262615140094151017">"<xliff:g id="APP_0">%1$s</xliff:g> колдонмосуна <xliff:g id="APP_2">%2$s</xliff:g> үлгүлөрүн көрсөтүүгө уруксат берилсинби?"</string>
<string name="slice_permission_text_1" msgid="6675965177075443714">"- <xliff:g id="APP">%1$s</xliff:g> колдонмосунун маалыматын окуйт"</string>
@@ -785,12 +794,18 @@
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Чоңойткуч терезесинин параметрлери"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Атайын мүмкүнчүлүктөрдү ачуу үчүн басыңыз. Бул баскычты Жөндөөлөрдөн өзгөртүңүз.\n\n"<annotation id="link">"Жөндөөлөрдү көрүү"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Баскычты убактылуу жашыра туруу үчүн экрандын четине жылдырыңыз"</string>
+ <!-- no translation found for accessibility_floating_button_undo (511112888715708241) -->
+ <skip />
+ <!-- no translation found for accessibility_floating_button_undo_message_text (3044079592757099698) -->
+ <skip />
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Жогорку сол жакка жылдыруу"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Жогорку оң жакка жылдырыңыз"</string>
<string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Төмөнкү сол жакка жылдыруу"</string>
<string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Төмөнкү оң жакка жылдырыңыз"</string>
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Ичине жылдырып, көрсөтүңүз"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Сыртка жылдырып, көрсөтүңүз"</string>
+ <!-- no translation found for accessibility_floating_button_action_remove_menu (6730432848162552135) -->
+ <skip />
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"өчүрүү/күйгүзүү"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Түзмөктү башкаруу элементтери"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Башкаруу элементтери кошула турган колдонмону тандоо"</string>
@@ -933,6 +948,10 @@
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Мобилдик трафик"</string>
<string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Туташты"</string>
+ <!-- no translation found for mobile_data_temp_connection_active (4590222725908806824) -->
+ <skip />
+ <!-- no translation found for mobile_data_poor_connection (819617772268371434) -->
+ <skip />
<string name="mobile_data_off_summary" msgid="3663995422004150567">"Мобилдик трафик автоматтык түрдө туташтырылбайт"</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"Байланыш жок"</string>
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"Башка тармактар жеткиликсиз"</string>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index 4fc25e2..d7dbb86 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -248,7 +248,8 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"ຄວາມແຈ້ງ"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"ການປີ້ນສີ"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"ການແກ້ໄຂສີ"</string>
- <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"ຕັ້ງຄ່າຜູ້ໃຊ້"</string>
+ <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) -->
+ <skip />
<string name="quick_settings_done" msgid="2163641301648855793">"ແລ້ວໆ"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"ປິດ"</string>
<string name="quick_settings_connected" msgid="3873605509184830379">"ເຊື່ອມຕໍ່ແລ້ວ"</string>
@@ -727,6 +728,14 @@
<string name="mobile_data_disable_title" msgid="5366476131671617790">"ປິດອິນເຕີເນັດມືຖືໄວ້ບໍ?"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"ທ່ານຈະບໍ່ມີສິດເຂົ້າເຖິງຂໍ້ມູນ ຫຼື ອິນເຕີເນັດຜ່ານ <xliff:g id="CARRIER">%s</xliff:g>. ອິນເຕີເນັດຈະສາມາດໃຊ້ໄດ້ຜ່ານ Wi-Fi ເທົ່ານັ້ນ."</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"ຜູ້ໃຫ້ບໍລິການຂອງທ່ານ"</string>
+ <!-- no translation found for auto_data_switch_disable_title (5146527155665190652) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_disable_message (5885533647399535852) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_negative_button (2370876875999891444) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_positive_button (8531782041263087564) -->
+ <skip />
<string name="touch_filtered_warning" msgid="8119511393338714836">"ເນື່ອງຈາກມີແອັບໃດໜຶ່ງກຳລັງຂັດຂວາງການຂໍອະນຸຍາດ, ການຕັ້ງຄ່າຈຶ່ງບໍ່ສາມາດຢັ້ງຢືນການຕອບຮັບຂອງທ່ານໄດ້."</string>
<string name="slice_permission_title" msgid="3262615140094151017">"ອະນຸຍາດ <xliff:g id="APP_0">%1$s</xliff:g> ໃຫ້ສະແດງ <xliff:g id="APP_2">%2$s</xliff:g> ສະໄລ້ບໍ?"</string>
<string name="slice_permission_text_1" msgid="6675965177075443714">"- ມັນສາມາດອ່ານຂໍ້ມູນຈາກ <xliff:g id="APP">%1$s</xliff:g>"</string>
@@ -785,12 +794,18 @@
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"ການຕັ້ງຄ່າໜ້າຈໍຂະຫຍາຍ"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"ແຕະເພື່ອເປີດຄຸນສົມບັດການຊ່ວຍເຂົ້າເຖິງ. ປັບແຕ່ງ ຫຼື ປ່ຽນປຸ່ມນີ້ໃນການຕັ້ງຄ່າ.\n\n"<annotation id="link">"ເບິ່ງການຕັ້ງຄ່າ"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"ຍ້າຍປຸ່ມໄປໃສ່ຂອບເພື່ອເຊື່ອງມັນຊົ່ວຄາວ"</string>
+ <!-- no translation found for accessibility_floating_button_undo (511112888715708241) -->
+ <skip />
+ <!-- no translation found for accessibility_floating_button_undo_message_text (3044079592757099698) -->
+ <skip />
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"ຍ້າຍຊ້າຍເທິງ"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"ຍ້າຍຂວາເທິງ"</string>
<string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"ຍ້າຍຊ້າຍລຸ່ມ"</string>
<string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"ຍ້າຍຂວາລຸ່ມ"</string>
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"ຍ້າຍອອກຂອບ ແລະ ເຊື່ອງ"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"ຍ້າຍອອກຂອບ ແລະ ສະແດງ"</string>
+ <!-- no translation found for accessibility_floating_button_action_remove_menu (6730432848162552135) -->
+ <skip />
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"ສະຫຼັບ"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"ການຄວບຄຸມອຸປະກອນ"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"ເລືອກແອັບເພື່ອເພີ່ມການຄວບຄຸມ"</string>
@@ -933,6 +948,10 @@
<string name="mobile_data_settings_title" msgid="3955246641380064901">"ອິນເຕີເນັດມືຖື"</string>
<string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"ເຊື່ອມຕໍ່ແລ້ວ"</string>
+ <!-- no translation found for mobile_data_temp_connection_active (4590222725908806824) -->
+ <skip />
+ <!-- no translation found for mobile_data_poor_connection (819617772268371434) -->
+ <skip />
<string name="mobile_data_off_summary" msgid="3663995422004150567">"ຈະບໍ່ເຊື່ອມຕໍ່ອິນເຕີເນັດມືຖືອັດຕະໂນມັດ"</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"ບໍ່ມີການເຊື່ອມຕໍ່"</string>
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"ບໍ່ມີເຄືອຂ່າຍອື່ນທີ່ສາມາດໃຊ້ໄດ້"</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index b9d6f33..e631ce2 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -248,7 +248,8 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Šviesumas"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Spalvų inversija"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Spalvų taisymas"</string>
- <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Naudotojo nustatymai"</string>
+ <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) -->
+ <skip />
<string name="quick_settings_done" msgid="2163641301648855793">"Atlikta"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Uždaryti"</string>
<string name="quick_settings_connected" msgid="3873605509184830379">"Prijungtas"</string>
@@ -727,6 +728,14 @@
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Išjungti mobiliojo ryšio duomenis?"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"Naudodamiesi „<xliff:g id="CARRIER">%s</xliff:g>“ paslaugomis neturėsite galimybės pasiekti duomenų arba interneto. Internetą galėsite naudoti tik prisijungę prie „Wi-Fi“."</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"savo operatoriaus"</string>
+ <!-- no translation found for auto_data_switch_disable_title (5146527155665190652) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_disable_message (5885533647399535852) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_negative_button (2370876875999891444) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_positive_button (8531782041263087564) -->
+ <skip />
<string name="touch_filtered_warning" msgid="8119511393338714836">"Kadangi programa užstoja leidimo užklausą, nustatymuose negalima patvirtinti jūsų atsakymo."</string>
<string name="slice_permission_title" msgid="3262615140094151017">"Leisti „<xliff:g id="APP_0">%1$s</xliff:g>“ rodyti „<xliff:g id="APP_2">%2$s</xliff:g>“ fragmentus?"</string>
<string name="slice_permission_text_1" msgid="6675965177075443714">"- Gali nuskaityti informaciją iš „<xliff:g id="APP">%1$s</xliff:g>“"</string>
@@ -785,12 +794,18 @@
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Didinimo lango nustatymai"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Palietę atidarykite pritaikymo neįgaliesiems funkcijas. Tinkinkite arba pakeiskite šį mygtuką nustatymuose.\n\n"<annotation id="link">"Žr. nustatymus"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Perkelkite mygtuką prie krašto, kad laikinai jį paslėptumėte"</string>
+ <!-- no translation found for accessibility_floating_button_undo (511112888715708241) -->
+ <skip />
+ <!-- no translation found for accessibility_floating_button_undo_message_text (3044079592757099698) -->
+ <skip />
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Perkelti į viršų kairėje"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Perkelti į viršų dešinėje"</string>
<string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Perkelti į apačią kairėje"</string>
<string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Perkelti į apačią dešinėje"</string>
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Perkelti į kraštą ir slėpti"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Perkelti iš krašto ir rodyti"</string>
+ <!-- no translation found for accessibility_floating_button_action_remove_menu (6730432848162552135) -->
+ <skip />
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"perjungti"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Įrenginio valdikliai"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Pasirinkite programą, kad pridėtumėte valdiklių"</string>
@@ -933,6 +948,10 @@
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobiliojo ryšio duomenys"</string>
<string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Prisijungta"</string>
+ <!-- no translation found for mobile_data_temp_connection_active (4590222725908806824) -->
+ <skip />
+ <!-- no translation found for mobile_data_poor_connection (819617772268371434) -->
+ <skip />
<string name="mobile_data_off_summary" msgid="3663995422004150567">"Naud. mob. r. duomenis nebus autom. prisijungiama"</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"Nėra ryšio"</string>
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"Nėra kitų pasiekiamų tinklų"</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 882ff7c..0a08654 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -248,7 +248,8 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Spilgtums"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Krāsu inversija"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Krāsu korekcija"</string>
- <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Lietotāja iestatījumi"</string>
+ <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) -->
+ <skip />
<string name="quick_settings_done" msgid="2163641301648855793">"Gatavs"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Aizvērt"</string>
<string name="quick_settings_connected" msgid="3873605509184830379">"Pievienota"</string>
@@ -727,6 +728,14 @@
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Vai izslēgt mobilos datus?"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"Izmantojot mobilo sakaru operatora <xliff:g id="CARRIER">%s</xliff:g> pakalpojumus, nevarēsiet piekļūt datiem vai internetam. Internetam varēsiet piekļūt, tikai izmantojot Wi-Fi savienojumu."</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"jūsu mobilo sakaru operators"</string>
+ <!-- no translation found for auto_data_switch_disable_title (5146527155665190652) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_disable_message (5885533647399535852) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_negative_button (2370876875999891444) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_positive_button (8531782041263087564) -->
+ <skip />
<string name="touch_filtered_warning" msgid="8119511393338714836">"Lietotne Iestatījumi nevar verificēt jūsu atbildi, jo cita lietotne aizsedz atļaujas pieprasījumu."</string>
<string name="slice_permission_title" msgid="3262615140094151017">"Vai atļaut lietotnei <xliff:g id="APP_0">%1$s</xliff:g> rādīt lietotnes <xliff:g id="APP_2">%2$s</xliff:g> sadaļas?"</string>
<string name="slice_permission_text_1" msgid="6675965177075443714">"- Var lasīt informāciju no lietotnes <xliff:g id="APP">%1$s</xliff:g>"</string>
@@ -785,12 +794,18 @@
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Lupas loga iestatījumi"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Atveriet pieejamības funkcijas. Pielāgojiet vai aizstājiet šo pogu iestatījumos.\n\n"<annotation id="link">"Skatīt iestatījumus"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Lai īslaicīgi paslēptu pogu, pārvietojiet to uz malu"</string>
+ <!-- no translation found for accessibility_floating_button_undo (511112888715708241) -->
+ <skip />
+ <!-- no translation found for accessibility_floating_button_undo_message_text (3044079592757099698) -->
+ <skip />
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Pārvietot augšpusē pa kreisi"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Pārvietot augšpusē pa labi"</string>
<string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Pārvietot apakšpusē pa kreisi"</string>
<string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Pārvietot apakšpusē pa labi"</string>
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Pārvietot uz malu un paslēpt"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Pārvietot no malas un parādīt"</string>
+ <!-- no translation found for accessibility_floating_button_action_remove_menu (6730432848162552135) -->
+ <skip />
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"pārslēgt"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Ierīču vadīklas"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Izvēlieties lietotni, lai pievienotu vadīklas"</string>
@@ -933,6 +948,10 @@
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobilie dati"</string>
<string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Ir izveidots savienojums"</string>
+ <!-- no translation found for mobile_data_temp_connection_active (4590222725908806824) -->
+ <skip />
+ <!-- no translation found for mobile_data_poor_connection (819617772268371434) -->
+ <skip />
<string name="mobile_data_off_summary" msgid="3663995422004150567">"Mobilo datu savienojums netiks veidots automātiski"</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"Nav savienojuma"</string>
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"Nav pieejams neviens cits tīkls"</string>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index 0d98dc6..e714055 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -248,7 +248,8 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Осветленост"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Инверзија на боите"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Корекција на боите"</string>
- <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Кориснички поставки"</string>
+ <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) -->
+ <skip />
<string name="quick_settings_done" msgid="2163641301648855793">"Готово"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Затвори"</string>
<string name="quick_settings_connected" msgid="3873605509184830379">"Поврзано"</string>
@@ -727,6 +728,14 @@
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Да се исклучи мобилниот интернет?"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"Нема да имате пристап до податоците или интернетот преку <xliff:g id="CARRIER">%s</xliff:g>. Интернетот ќе биде достапен само преку Wi-Fi."</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"вашиот оператор"</string>
+ <!-- no translation found for auto_data_switch_disable_title (5146527155665190652) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_disable_message (5885533647399535852) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_negative_button (2370876875999891444) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_positive_button (8531782041263087564) -->
+ <skip />
<string name="touch_filtered_warning" msgid="8119511393338714836">"Бидејќи апликацијата го прикрива барањето за дозвола, „Поставките“ не може да го потврдат вашиот одговор."</string>
<string name="slice_permission_title" msgid="3262615140094151017">"Да се дозволи <xliff:g id="APP_0">%1$s</xliff:g> да прикажува делови од <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
<string name="slice_permission_text_1" msgid="6675965177075443714">"- Може да чита информации од <xliff:g id="APP">%1$s</xliff:g>"</string>
@@ -785,12 +794,18 @@
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Поставки за прозорец за лупа"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Допрете за функциите за пристапност. Приспособете или заменете го копчево во „Поставки“.\n\n"<annotation id="link">"Прикажи поставки"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Преместете го копчето до работ за да го сокриете привремено"</string>
+ <!-- no translation found for accessibility_floating_button_undo (511112888715708241) -->
+ <skip />
+ <!-- no translation found for accessibility_floating_button_undo_message_text (3044079592757099698) -->
+ <skip />
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Премести горе лево"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Премести горе десно"</string>
<string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Премести долу лево"</string>
<string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Премести долу десно"</string>
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Премести до работ и сокриј"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Премести над работ и прикажи"</string>
+ <!-- no translation found for accessibility_floating_button_action_remove_menu (6730432848162552135) -->
+ <skip />
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"вклучување/исклучување"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Контроли за уредите"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Изберете апликација за да додадете контроли"</string>
@@ -933,6 +948,10 @@
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Мобилен интернет"</string>
<string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Поврзано"</string>
+ <!-- no translation found for mobile_data_temp_connection_active (4590222725908806824) -->
+ <skip />
+ <!-- no translation found for mobile_data_poor_connection (819617772268371434) -->
+ <skip />
<string name="mobile_data_off_summary" msgid="3663995422004150567">"Мобилниот интернет не може да се поврзе автоматски"</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"Нема интернет-врска"</string>
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"Нема други достапни мрежи"</string>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index 868d759..666e601 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -248,7 +248,7 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"തെളിച്ചം"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"നിറം വിപരീതമാക്കൽ"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"നിറം ശരിയാക്കൽ"</string>
- <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"ഉപയോക്തൃ ക്രമീകരണം"</string>
+ <string name="quick_settings_more_user_settings" msgid="7634653308485206306">"ഉപയോക്താക്കളെ മാനേജ് ചെയ്യുക"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"പൂർത്തിയാക്കി"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"അടയ്ക്കുക"</string>
<string name="quick_settings_connected" msgid="3873605509184830379">"കണക്റ്റുചെയ്തു"</string>
@@ -727,6 +727,14 @@
<string name="mobile_data_disable_title" msgid="5366476131671617790">"മൊബൈൽ ഡാറ്റ ഓഫാക്കണോ?"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"നിങ്ങൾക്ക് ഡാറ്റയിലേക്ക് ആക്സസോ അല്ലെങ്കിൽ <xliff:g id="CARRIER">%s</xliff:g> മുഖേനയുള്ള ഇന്റർനെറ്റോ ഉണ്ടാകില്ല. വൈഫൈ മുഖേന മാത്രമായിരിക്കും ഇന്റർനെറ്റ് ലഭ്യത."</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"നിങ്ങളുടെ കാരിയർ"</string>
+ <!-- no translation found for auto_data_switch_disable_title (5146527155665190652) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_disable_message (5885533647399535852) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_negative_button (2370876875999891444) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_positive_button (8531782041263087564) -->
+ <skip />
<string name="touch_filtered_warning" msgid="8119511393338714836">"അനുമതി അഭ്യർത്ഥനയെ ഒരു ആപ്പ് മറയ്ക്കുന്നതിനാൽ, ക്രമീകരണത്തിന് നിങ്ങളുടെ പ്രതികരണം പരിശോധിച്ചുറപ്പിക്കാനാകില്ല."</string>
<string name="slice_permission_title" msgid="3262615140094151017">"<xliff:g id="APP_2">%2$s</xliff:g> സ്ലൈസുകൾ കാണിക്കാൻ <xliff:g id="APP_0">%1$s</xliff:g>-നെ അനുവദിക്കണോ?"</string>
<string name="slice_permission_text_1" msgid="6675965177075443714">"- ഇതിന് <xliff:g id="APP">%1$s</xliff:g>-ൽ നിന്ന് വിവരങ്ങൾ വായിക്കാനാകും"</string>
@@ -785,12 +793,18 @@
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"മാഗ്നിഫയർ വിൻഡോ ക്രമീകരണം"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"ഉപയോഗസഹായി ഫീച്ചർ തുറക്കാൻ ടാപ്പ് ചെയ്യൂ. ക്രമീകരണത്തിൽ ഈ ബട്ടൺ ഇഷ്ടാനുസൃതമാക്കാം, മാറ്റാം.\n\n"<annotation id="link">"ക്രമീകരണം കാണൂ"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"തൽക്കാലം മറയ്ക്കുന്നതിന് ബട്ടൺ അരുകിലേക്ക് നീക്കുക"</string>
+ <!-- no translation found for accessibility_floating_button_undo (511112888715708241) -->
+ <skip />
+ <!-- no translation found for accessibility_floating_button_undo_message_text (3044079592757099698) -->
+ <skip />
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"മുകളിൽ ഇടതുഭാഗത്തേക്ക് നീക്കുക"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"മുകളിൽ വലതുഭാഗത്തേക്ക് നീക്കുക"</string>
<string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"ചുവടെ ഇടതുഭാഗത്തേക്ക് നീക്കുക"</string>
<string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"ചുവടെ വലതുഭാഗത്തേക്ക് നീക്കുക"</string>
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"എഡ്ജിലേക്ക് നീക്കി മറയ്ക്കുക"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"എഡ്ജിൽ നിന്ന് നീക്കി കാണിക്കൂ"</string>
+ <!-- no translation found for accessibility_floating_button_action_remove_menu (6730432848162552135) -->
+ <skip />
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"മാറ്റുക"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"ഉപകരണ നിയന്ത്രണങ്ങൾ"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"നിയന്ത്രണങ്ങൾ ചേർക്കാൻ ആപ്പ് തിരഞ്ഞെടുക്കുക"</string>
@@ -933,6 +947,10 @@
<string name="mobile_data_settings_title" msgid="3955246641380064901">"മൊബൈൽ ഡാറ്റ"</string>
<string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"കണക്റ്റ് ചെയ്തു"</string>
+ <!-- no translation found for mobile_data_temp_connection_active (4590222725908806824) -->
+ <skip />
+ <!-- no translation found for mobile_data_poor_connection (819617772268371434) -->
+ <skip />
<string name="mobile_data_off_summary" msgid="3663995422004150567">"മൊബൈൽ ഡാറ്റ സ്വയം കണക്റ്റ് ചെയ്യില്ല"</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"കണക്ഷനില്ല"</string>
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"മറ്റ് നെറ്റ്വർക്കുകളൊന്നും ലഭ്യമല്ല"</string>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index 25929e6..769cdda 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -248,7 +248,7 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Тодрол"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Өнгө хувиргалт"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Өнгө тохируулга"</string>
- <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Хэрэглэгчийн тохиргоо"</string>
+ <string name="quick_settings_more_user_settings" msgid="7634653308485206306">"Хэрэглэгчдийг удирдах"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Дууссан"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Хаах"</string>
<string name="quick_settings_connected" msgid="3873605509184830379">"Холбогдсон"</string>
@@ -727,6 +727,14 @@
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Мобайл датаг унтраах уу?"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"Та <xliff:g id="CARRIER">%s</xliff:g>-р дата эсвэл интернэтэд хандах боломжгүй болно. Интернэтэд зөвхөн Wi-Fi-р холбогдох боломжтой болно."</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"таны оператор компани"</string>
+ <!-- no translation found for auto_data_switch_disable_title (5146527155665190652) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_disable_message (5885533647399535852) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_negative_button (2370876875999891444) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_positive_button (8531782041263087564) -->
+ <skip />
<string name="touch_filtered_warning" msgid="8119511393338714836">"Апп нь зөвшөөрлийн хүсэлтийг танихгүй байгаа тул Тохиргооноос таны хариултыг баталгаажуулах боломжгүй байна."</string>
<string name="slice_permission_title" msgid="3262615140094151017">"<xliff:g id="APP_0">%1$s</xliff:g>-д <xliff:g id="APP_2">%2$s</xliff:g>-н хэсгүүдийг (slices) харуулахыг зөвшөөрөх үү?"</string>
<string name="slice_permission_text_1" msgid="6675965177075443714">"- Энэ нь <xliff:g id="APP">%1$s</xliff:g>-с мэдээлэл унших боломжтой"</string>
@@ -785,12 +793,18 @@
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Томруулагчийн цонхны тохиргоо"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Хандалтын онцлогуудыг нээхийн тулд товшино уу. Энэ товчлуурыг Тохиргоо хэсэгт өөрчилж эсвэл солиорой.\n\n"<annotation id="link">"Тохиргоог харах"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Үүнийг түр нуухын тулд товчлуурыг зах руу зөөнө үү"</string>
+ <!-- no translation found for accessibility_floating_button_undo (511112888715708241) -->
+ <skip />
+ <!-- no translation found for accessibility_floating_button_undo_message_text (3044079592757099698) -->
+ <skip />
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Зүүн дээш зөөх"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Баруун дээш зөөх"</string>
<string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Зүүн доош зөөх"</string>
<string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Баруун доош зөөх"</string>
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Ирмэг рүү зөөж, нуух"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Ирмэгээс гаргаж, харуулах"</string>
+ <!-- no translation found for accessibility_floating_button_action_remove_menu (6730432848162552135) -->
+ <skip />
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"асаах/унтраах"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Төхөөрөмжийн хяналт"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Хяналтууд нэмэхийн тулд аппыг сонгоно уу"</string>
@@ -933,6 +947,10 @@
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Мобайл дата"</string>
<string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Холбогдсон"</string>
+ <!-- no translation found for mobile_data_temp_connection_active (4590222725908806824) -->
+ <skip />
+ <!-- no translation found for mobile_data_poor_connection (819617772268371434) -->
+ <skip />
<string name="mobile_data_off_summary" msgid="3663995422004150567">"Мобайл дата автоматаар холбогдохгүй"</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"Холболт алга"</string>
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"Өөр боломжтой сүлжээ байхгүй байна"</string>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index c6e99a7..d45b1e5 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -248,7 +248,8 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"चमक"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"कलर इन्व्हर्जन"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"रंग सुधारणा"</string>
- <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"वापरकर्ता सेटिंग्ज"</string>
+ <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) -->
+ <skip />
<string name="quick_settings_done" msgid="2163641301648855793">"पूर्ण झाले"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"बंद करा"</string>
<string name="quick_settings_connected" msgid="3873605509184830379">"कनेक्ट केलेले"</string>
@@ -727,6 +728,14 @@
<string name="mobile_data_disable_title" msgid="5366476131671617790">"मोबाइल डेटा बंद करायचा?"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"तुम्हाला <xliff:g id="CARRIER">%s</xliff:g> मधून डेटा किंवा इंटरनेटचा अॅक्सेस नसेल. इंटरनेट फक्त वाय-फाय मार्फत उपलब्ध असेल."</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"तुमचा वाहक"</string>
+ <!-- no translation found for auto_data_switch_disable_title (5146527155665190652) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_disable_message (5885533647399535852) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_negative_button (2370876875999891444) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_positive_button (8531782041263087564) -->
+ <skip />
<string name="touch_filtered_warning" msgid="8119511393338714836">"अॅप परवानगी विनंती अस्पष्ट करत असल्याने, सेटिंग्ज तुमचा प्रतिसाद पडताळू शकत नाहीत."</string>
<string name="slice_permission_title" msgid="3262615140094151017">"<xliff:g id="APP_0">%1$s</xliff:g> ला <xliff:g id="APP_2">%2$s</xliff:g> चे तुकडे दाखवण्याची अनुमती द्यायची का?"</string>
<string name="slice_permission_text_1" msgid="6675965177075443714">"- ते <xliff:g id="APP">%1$s</xliff:g> ची माहिती वाचू शकते"</string>
@@ -785,12 +794,18 @@
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"मॅग्निफायर विंडो सेटिंग्ज"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"अॅक्सेसिबिलिटी वैशिष्ट्ये उघडण्यासाठी, टॅप करा. सेटिंग्जमध्ये हे बटण कस्टमाइझ करा किंवा बदला.\n\n"<annotation id="link">"सेटिंग्ज पहा"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"बटण तात्पुरते लपवण्यासाठी ते कोपर्यामध्ये हलवा"</string>
+ <!-- no translation found for accessibility_floating_button_undo (511112888715708241) -->
+ <skip />
+ <!-- no translation found for accessibility_floating_button_undo_message_text (3044079592757099698) -->
+ <skip />
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"वर डावीकडे हलवा"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"वर उजवीकडे हलवा"</string>
<string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"तळाशी डावीकडे हलवा"</string>
<string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"तळाशी उजवीकडे हलवा"</string>
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"एजवर हलवा आणि लपवा"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"एजवर हलवा आणि दाखवा"</string>
+ <!-- no translation found for accessibility_floating_button_action_remove_menu (6730432848162552135) -->
+ <skip />
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"टॉगल करा"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"डिव्हाइस नियंत्रणे"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"नियंत्रणे जोडण्यासाठी ॲप निवडा"</string>
@@ -933,6 +948,10 @@
<string name="mobile_data_settings_title" msgid="3955246641380064901">"मोबाइल डेटा"</string>
<string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"कनेक्ट केले आहे"</string>
+ <!-- no translation found for mobile_data_temp_connection_active (4590222725908806824) -->
+ <skip />
+ <!-- no translation found for mobile_data_poor_connection (819617772268371434) -->
+ <skip />
<string name="mobile_data_off_summary" msgid="3663995422004150567">"मोबाइल डेटा ऑटो-कनेक्ट होणार नाही"</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"कोणतेही कनेक्शन नाही"</string>
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"इतर कोणतेही नेटवर्क उपलब्ध नाहीत"</string>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index 99349b157..9e43396 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -248,7 +248,8 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Kecerahan"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Penyongsangan warna"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Pembetulan warna"</string>
- <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Tetapan pengguna"</string>
+ <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) -->
+ <skip />
<string name="quick_settings_done" msgid="2163641301648855793">"Selesai"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Tutup"</string>
<string name="quick_settings_connected" msgid="3873605509184830379">"Disambungkan"</string>
@@ -727,6 +728,14 @@
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Matikan data mudah alih?"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"Anda tidak akan mempunyai akses kepada data atau Internet melalui <xliff:g id="CARRIER">%s</xliff:g>. Internet hanya tersedia melaui Wi-Fi."</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"pembawa anda"</string>
+ <!-- no translation found for auto_data_switch_disable_title (5146527155665190652) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_disable_message (5885533647399535852) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_negative_button (2370876875999891444) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_positive_button (8531782041263087564) -->
+ <skip />
<string name="touch_filtered_warning" msgid="8119511393338714836">"Oleh sebab apl melindungi permintaan kebenaran, Tetapan tidak dapat mengesahkan jawapan anda."</string>
<string name="slice_permission_title" msgid="3262615140094151017">"Benarkan <xliff:g id="APP_0">%1$s</xliff:g> menunjukkan <xliff:g id="APP_2">%2$s</xliff:g> hirisan?"</string>
<string name="slice_permission_text_1" msgid="6675965177075443714">"- Hos hirisan boleh membaca maklumat daripada <xliff:g id="APP">%1$s</xliff:g>"</string>
@@ -785,12 +794,18 @@
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Tetapan tetingkap penggadang"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Ketik untuk membuka ciri kebolehaksesan. Sesuaikan/gantikan butang ini dalam Tetapan.\n\n"<annotation id="link">"Lihat tetapan"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Gerakkan butang ke tepi untuk disembunyikan buat sementara waktu"</string>
+ <!-- no translation found for accessibility_floating_button_undo (511112888715708241) -->
+ <skip />
+ <!-- no translation found for accessibility_floating_button_undo_message_text (3044079592757099698) -->
+ <skip />
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Alihkan ke atas sebelah kiri"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Alihkan ke atas sebelah kanan"</string>
<string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Alihkan ke bawah sebelah kiri"</string>
<string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Alihkan ke bawah sebelah kanan"</string>
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Alihkan ke tepi dan sorokkan"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Alihkan ke tepi dan tunjukkan"</string>
+ <!-- no translation found for accessibility_floating_button_action_remove_menu (6730432848162552135) -->
+ <skip />
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"togol"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Kawalan peranti"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Pilih apl untuk menambahkan kawalan"</string>
@@ -933,6 +948,10 @@
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Data mudah alih"</string>
<string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Disambungkan"</string>
+ <!-- no translation found for mobile_data_temp_connection_active (4590222725908806824) -->
+ <skip />
+ <!-- no translation found for mobile_data_poor_connection (819617772268371434) -->
+ <skip />
<string name="mobile_data_off_summary" msgid="3663995422004150567">"Data mudah alih tidak akan autosambung"</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"Tiada sambungan"</string>
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"Tiada rangkaian lain yang tersedia"</string>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index f30846a..8f404b8 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -248,7 +248,8 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"အလင်းတောက်ပမှု"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"အရောင်ပြောင်းပြန်ပြုလုပ်ရန်"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"အရောင် အမှန်ပြင်ခြင်း"</string>
- <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"အသုံးပြုသူ ဆက်တင်များ"</string>
+ <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) -->
+ <skip />
<string name="quick_settings_done" msgid="2163641301648855793">"ပြီးပါပြီ"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"ပိတ်ရန်"</string>
<string name="quick_settings_connected" msgid="3873605509184830379">"ချိတ်ဆက်ထား"</string>
@@ -727,6 +728,14 @@
<string name="mobile_data_disable_title" msgid="5366476131671617790">"မိုဘိုင်းဒေတာ ပိတ်မလား။"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"<xliff:g id="CARRIER">%s</xliff:g> မှတစ်ဆင့် ဒေတာ သို့မဟုတ် အင်တာနက်ကို မသုံးနိုင်ပါ။ Wi-Fi ဖြင့်သာ အင်တာနက် သုံးနိုင်သည်။"</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"သင်၏ ဝန်ဆောင်မှုပေးသူ"</string>
+ <!-- no translation found for auto_data_switch_disable_title (5146527155665190652) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_disable_message (5885533647399535852) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_negative_button (2370876875999891444) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_positive_button (8531782041263087564) -->
+ <skip />
<string name="touch_filtered_warning" msgid="8119511393338714836">"အပလီကေးရှင်းတစ်ခုက ခွင့်ပြုချက်တောင်းခံမှုကို ပိတ်ထားသောကြောင့် ဆက်တင်များသည် သင်၏ လုပ်ဆောင်ကို တုံ့ပြန်နိုင်ခြင်းမရှိပါ။"</string>
<string name="slice_permission_title" msgid="3262615140094151017">"<xliff:g id="APP_0">%1$s</xliff:g> အား <xliff:g id="APP_2">%2$s</xliff:g> ၏အချပ်များ ပြသခွင့်ပြုပါသလား။"</string>
<string name="slice_permission_text_1" msgid="6675965177075443714">"- ၎င်းသည် <xliff:g id="APP">%1$s</xliff:g> မှ အချက်အလက်ကို ဖတ်နိုင်သည်"</string>
@@ -785,12 +794,18 @@
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"မှန်ဘီလူးဝင်းဒိုး ဆက်တင်များ"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"အများသုံးစွဲနိုင်မှုဆိုင်ရာ ဝန်ဆောင်မှုများ ဖွင့်ရန် တို့ပါ။ ဆက်တင်များတွင် ဤခလုတ်ကို စိတ်ကြိုက်ပြင်ပါ (သို့) လဲပါ။\n\n"<annotation id="link">"ဆက်တင်များ ကြည့်ရန်"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"ခလုတ်ကို ယာယီဝှက်ရန် အစွန်းသို့ရွှေ့ပါ"</string>
+ <!-- no translation found for accessibility_floating_button_undo (511112888715708241) -->
+ <skip />
+ <!-- no translation found for accessibility_floating_button_undo_message_text (3044079592757099698) -->
+ <skip />
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"ဘယ်ဘက်ထိပ်သို့ ရွှေ့ရန်"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"ညာဘက်ထိပ်သို့ ရွှေ့ရန်"</string>
<string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"ဘယ်ဘက်အောက်ခြေသို့ ရွှေ့ရန်"</string>
<string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"ညာဘက်အောက်ခြေသို့ ရွှေ့ရန်"</string>
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"အစွန်းသို့ရွှေ့ပြီး ဝှက်ရန်"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"အစွန်းမှရွှေ့ပြီး ပြရန်"</string>
+ <!-- no translation found for accessibility_floating_button_action_remove_menu (6730432848162552135) -->
+ <skip />
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"ပြောင်းရန်"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"စက်ထိန်းစနစ်"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"ထိန်းချုပ်မှုများထည့်ရန် အက်ပ်ရွေးခြင်း"</string>
@@ -933,6 +948,10 @@
<string name="mobile_data_settings_title" msgid="3955246641380064901">"မိုဘိုင်းဒေတာ"</string>
<string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"ချိတ်ဆက်ထားသည်"</string>
+ <!-- no translation found for mobile_data_temp_connection_active (4590222725908806824) -->
+ <skip />
+ <!-- no translation found for mobile_data_poor_connection (819617772268371434) -->
+ <skip />
<string name="mobile_data_off_summary" msgid="3663995422004150567">"မိုဘိုင်းဒေတာ အော်တိုမချိတ်ပါ"</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"ချိတ်ဆက်မှုမရှိပါ"</string>
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"အခြားကွန်ရက်များ မရှိပါ"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 117c864..94b8e90 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -248,7 +248,8 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Lysstyrke"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Fargeinvertering"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Fargekorrigering"</string>
- <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Brukerinnstillinger"</string>
+ <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) -->
+ <skip />
<string name="quick_settings_done" msgid="2163641301648855793">"Ferdig"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Lukk"</string>
<string name="quick_settings_connected" msgid="3873605509184830379">"Tilkoblet"</string>
@@ -727,6 +728,14 @@
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Vil du slå av mobildata?"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"Du får ikke tilgang til data eller internett via <xliff:g id="CARRIER">%s</xliff:g>. Internett er bare tilgjengelig via Wifi."</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"operatøren din"</string>
+ <!-- no translation found for auto_data_switch_disable_title (5146527155665190652) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_disable_message (5885533647399535852) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_negative_button (2370876875999891444) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_positive_button (8531782041263087564) -->
+ <skip />
<string name="touch_filtered_warning" msgid="8119511393338714836">"Fordi en app skjuler tillatelsesforespørselen, kan ikke Innstillinger bekrefte svaret ditt."</string>
<string name="slice_permission_title" msgid="3262615140094151017">"Vil du tillate at <xliff:g id="APP_0">%1$s</xliff:g> viser <xliff:g id="APP_2">%2$s</xliff:g>-utsnitt?"</string>
<string name="slice_permission_text_1" msgid="6675965177075443714">"– Den kan lese informasjon fra <xliff:g id="APP">%1$s</xliff:g>"</string>
@@ -785,12 +794,18 @@
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Innstillinger for forstørringsvindu"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Trykk for å åpne tilgj.funksjoner. Tilpass eller bytt knappen i Innstillinger.\n\n"<annotation id="link">"Se innstillingene"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Flytt knappen til kanten for å skjule den midlertidig"</string>
+ <!-- no translation found for accessibility_floating_button_undo (511112888715708241) -->
+ <skip />
+ <!-- no translation found for accessibility_floating_button_undo_message_text (3044079592757099698) -->
+ <skip />
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Flytt til øverst til venstre"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Flytt til øverst til høyre"</string>
<string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Flytt til nederst til venstre"</string>
<string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Flytt til nederst til høyre"</string>
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Flytt til kanten og skjul"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Flytt ut kanten og vis"</string>
+ <!-- no translation found for accessibility_floating_button_action_remove_menu (6730432848162552135) -->
+ <skip />
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"slå av/på"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Enhetsstyring"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Velg en app for å legge til kontroller"</string>
@@ -933,6 +948,10 @@
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobildata"</string>
<string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Tilkoblet"</string>
+ <!-- no translation found for mobile_data_temp_connection_active (4590222725908806824) -->
+ <skip />
+ <!-- no translation found for mobile_data_poor_connection (819617772268371434) -->
+ <skip />
<string name="mobile_data_off_summary" msgid="3663995422004150567">"Mobildata kobler ikke til automatisk"</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"Ingen tilkobling"</string>
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"Ingen andre nettverk er tilgjengelige"</string>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index 3519715..35937a9 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -248,7 +248,8 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"उज्यालपन"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"कलर इन्भर्सन"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"कलर करेक्सन"</string>
- <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"प्रयोगकर्तासम्बन्धी सेटिङ"</string>
+ <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) -->
+ <skip />
<string name="quick_settings_done" msgid="2163641301648855793">"भयो"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"बन्द गर्नुहोस्"</string>
<string name="quick_settings_connected" msgid="3873605509184830379">"जोडिएको"</string>
@@ -727,6 +728,14 @@
<string name="mobile_data_disable_title" msgid="5366476131671617790">"मोबाइल डेटा निष्क्रिय पार्ने हो?"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"तपाईं <xliff:g id="CARRIER">%s</xliff:g> मार्फत डेटा वा इन्टरनेट प्रयोग गर्न सक्नुहुने छैन। Wi-Fi मार्फत मात्र इन्टरनेट उपलब्ध हुने छ।"</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"तपाईंको सेवा प्रदायक"</string>
+ <!-- no translation found for auto_data_switch_disable_title (5146527155665190652) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_disable_message (5885533647399535852) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_negative_button (2370876875999891444) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_positive_button (8531782041263087564) -->
+ <skip />
<string name="touch_filtered_warning" msgid="8119511393338714836">"कुनै एपको कारणले अनुमतिसम्बन्धी अनुरोध बुझ्न गाह्रो भइरहेकोले सेटिङहरूले तपाईंको प्रतिक्रिया प्रमाणित गर्न सक्दैनन्।"</string>
<string name="slice_permission_title" msgid="3262615140094151017">"<xliff:g id="APP_0">%1$s</xliff:g> लाई <xliff:g id="APP_2">%2$s</xliff:g> का स्लाइसहरू देखाउन अनुमति दिने हो?"</string>
<string name="slice_permission_text_1" msgid="6675965177075443714">"- यसले <xliff:g id="APP">%1$s</xliff:g> बाट जानकारी पढ्न सक्छ"</string>
@@ -785,12 +794,18 @@
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"म्याग्निफायर विन्डोसम्बन्धी सेटिङ"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"सर्वसुलभता कायम गर्ने सुविधा खोल्न ट्याप गर्नुहोस्। सेटिङमा गई यो बटन कस्टमाइज गर्नुहोस् वा बदल्नुहोस्।\n\n"<annotation id="link">"सेटिङ हेर्नुहोस्"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"यो बटन केही बेर नदेखिने पार्न किनारातिर सार्नुहोस्"</string>
+ <!-- no translation found for accessibility_floating_button_undo (511112888715708241) -->
+ <skip />
+ <!-- no translation found for accessibility_floating_button_undo_message_text (3044079592757099698) -->
+ <skip />
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"सिरानको बायाँतिर सार्नुहोस्"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"सिरानको दायाँतिर सार्नुहोस्"</string>
<string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"पुछारको बायाँतिर सार्नुहोस्"</string>
<string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"पुछारको दायाँतिर सार्नुहोस्"</string>
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"किनारामा सार्नुहोस् र नदेखिने पार्नु…"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"किनाराबाट सार्नुहोस् र देखिने पार्नु…"</string>
+ <!-- no translation found for accessibility_floating_button_action_remove_menu (6730432848162552135) -->
+ <skip />
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"टगल गर्नुहोस्"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"डिभाइस नियन्त्रण गर्ने विजेटहरू"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"कन्ट्रोल थप्नु पर्ने एप छान्नुहोस्"</string>
@@ -933,6 +948,10 @@
<string name="mobile_data_settings_title" msgid="3955246641380064901">"मोबाइल डेटा"</string>
<string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"इन्टरनेटमा कनेक्ट गरिएको छ"</string>
+ <!-- no translation found for mobile_data_temp_connection_active (4590222725908806824) -->
+ <skip />
+ <!-- no translation found for mobile_data_poor_connection (819617772268371434) -->
+ <skip />
<string name="mobile_data_off_summary" msgid="3663995422004150567">"मोबाइल डेटा स्वतः कनेक्ट हुँदैन"</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"इन्टरनेट छैन"</string>
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"अन्य नेटवर्क उपलब्ध छैनन्"</string>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 3c85148..4de0331 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -248,7 +248,8 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Helderheid"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Kleurinversie"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Kleurcorrectie"</string>
- <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Gebruikersinstellingen"</string>
+ <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) -->
+ <skip />
<string name="quick_settings_done" msgid="2163641301648855793">"Klaar"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Sluiten"</string>
<string name="quick_settings_connected" msgid="3873605509184830379">"Verbonden"</string>
@@ -727,6 +728,14 @@
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Mobiele data uitzetten?"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"Je hebt dan geen toegang meer tot data of internet via <xliff:g id="CARRIER">%s</xliff:g>. Internet is alleen nog beschikbaar via wifi."</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"je provider"</string>
+ <!-- no translation found for auto_data_switch_disable_title (5146527155665190652) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_disable_message (5885533647399535852) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_negative_button (2370876875999891444) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_positive_button (8531782041263087564) -->
+ <skip />
<string name="touch_filtered_warning" msgid="8119511393338714836">"Aangezien een app een rechtenverzoek afdekt, kan Instellingen je reactie niet verifiëren."</string>
<string name="slice_permission_title" msgid="3262615140094151017">"<xliff:g id="APP_0">%1$s</xliff:g> toestaan om segmenten van <xliff:g id="APP_2">%2$s</xliff:g> te tonen?"</string>
<string name="slice_permission_text_1" msgid="6675965177075443714">"- Deze kan informatie lezen van <xliff:g id="APP">%1$s</xliff:g>"</string>
@@ -785,12 +794,18 @@
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Instellingen voor vergrotingsvenster"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Tik voor toegankelijkheidsfuncties. Wijzig of vervang deze knop via Instellingen.\n\n"<annotation id="link">"Naar Instellingen"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Knop naar de rand verplaatsen om deze tijdelijk te verbergen"</string>
+ <!-- no translation found for accessibility_floating_button_undo (511112888715708241) -->
+ <skip />
+ <!-- no translation found for accessibility_floating_button_undo_message_text (3044079592757099698) -->
+ <skip />
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Naar linksboven verplaatsen"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Naar rechtsboven verplaatsen"</string>
<string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Naar linksonder verplaatsen"</string>
<string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Naar rechtsonder verplaatsen"</string>
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Naar rand verplaatsen en verbergen"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Over rand verplaatsen en tonen"</string>
+ <!-- no translation found for accessibility_floating_button_action_remove_menu (6730432848162552135) -->
+ <skip />
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"schakelen"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Apparaatbediening"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Kies de app waaraan je bedieningselementen wilt toevoegen"</string>
@@ -933,6 +948,10 @@
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobiele data"</string>
<string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Verbonden"</string>
+ <!-- no translation found for mobile_data_temp_connection_active (4590222725908806824) -->
+ <skip />
+ <!-- no translation found for mobile_data_poor_connection (819617772268371434) -->
+ <skip />
<string name="mobile_data_off_summary" msgid="3663995422004150567">"Mobiele data maakt niet automatisch verbinding"</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"Geen verbinding"</string>
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"Geen andere netwerken beschikbaar"</string>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index 1cb3436..16941b8 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -248,7 +248,8 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"ଉଜ୍ଜ୍ୱଳତା"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"ରଙ୍ଗ ଇନଭାର୍ସନ"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"ରଙ୍ଗ ସଂଶୋଧନ"</string>
- <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"ଉପଯୋଗକର୍ତ୍ତା ସେଟିଂସ"</string>
+ <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) -->
+ <skip />
<string name="quick_settings_done" msgid="2163641301648855793">"ହୋଇଗଲା"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"ବନ୍ଦ କରନ୍ତୁ"</string>
<string name="quick_settings_connected" msgid="3873605509184830379">"ସଂଯୁକ୍ତ"</string>
@@ -727,6 +728,14 @@
<string name="mobile_data_disable_title" msgid="5366476131671617790">"ମୋବାଇଲ୍ ଡାଟା ବନ୍ଦ କରିବେ?"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"ଡାଟା କିମ୍ବା ଇଣ୍ଟରନେଟ୍କୁ <xliff:g id="CARRIER">%s</xliff:g> ଦ୍ଵାରା ଆପଣଙ୍କର ଆକ୍ସେସ୍ ରହିବ ନାହିଁ। ଇଣ୍ଟରନେଟ୍ କେବଳ ୱାଇ-ଫାଇ ମାଧ୍ୟମରେ ଉପଲବ୍ଧ ହେବ।"</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"ଆପଣଙ୍କ କେରିଅର୍"</string>
+ <!-- no translation found for auto_data_switch_disable_title (5146527155665190652) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_disable_message (5885533647399535852) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_negative_button (2370876875999891444) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_positive_button (8531782041263087564) -->
+ <skip />
<string name="touch_filtered_warning" msgid="8119511393338714836">"ଗୋଟିଏ ଆପ୍ ଏକ ଅନୁମତି ଅନୁରୋଧକୁ ଦେଖିବାରେ ବାଧା ଦେଉଥିବାରୁ, ସେଟିଙ୍ଗ ଆପଣଙ୍କ ଉତ୍ତରକୁ ଯାଞ୍ଚ କରିପାରିବ ନାହିଁ।"</string>
<string name="slice_permission_title" msgid="3262615140094151017">"<xliff:g id="APP_2">%2$s</xliff:g> ସ୍ଲାଇସ୍କୁ ଦେଖାଇବା ପାଇଁ <xliff:g id="APP_0">%1$s</xliff:g>କୁ ଅନୁମତି ଦେବେ?"</string>
<string name="slice_permission_text_1" msgid="6675965177075443714">"- ଏହା <xliff:g id="APP">%1$s</xliff:g>ରୁ ସୂଚନାକୁ ପଢ଼ିପାରିବ"</string>
@@ -785,12 +794,18 @@
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"ମ୍ୟାଗ୍ନିଫାୟର ୱିଣ୍ଡୋର ସେଟିଂସ"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"ଆକ୍ସେସିବିଲିଟୀ ଫିଚର ଖୋଲିବାକୁ ଟାପ କରନ୍ତୁ। ସେଟିଂସରେ ଏହି ବଟନକୁ କଷ୍ଟମାଇଜ କର କିମ୍ବା ବଦଳାଅ।\n\n"<annotation id="link">"ସେଟିଂସ ଦେଖନ୍ତୁ"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"ବଟନକୁ ଅସ୍ଥାୟୀ ଭାବେ ଲୁଚାଇବା ପାଇଁ ଏହାକୁ ଗୋଟିଏ ଧାରକୁ ମୁଭ୍ କରନ୍ତୁ"</string>
+ <!-- no translation found for accessibility_floating_button_undo (511112888715708241) -->
+ <skip />
+ <!-- no translation found for accessibility_floating_button_undo_message_text (3044079592757099698) -->
+ <skip />
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"ଶୀର୍ଷ ବାମକୁ ମୁଭ୍ କରନ୍ତୁ"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"ଶୀର୍ଷ ଡାହାଣକୁ ମୁଭ୍ କରନ୍ତୁ"</string>
<string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"ନିମ୍ନ ବାମକୁ ମୁଭ୍ କରନ୍ତୁ"</string>
<string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"ନିମ୍ନ ଡାହାଣକୁ ମୁଭ୍ କରନ୍ତୁ"</string>
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"ଧାରକୁ ମୁଭ୍ କରି ଲୁଚାନ୍ତୁ"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"ଧାର ବାହାରକୁ ମୁଭ୍ କରି ଦେଖାନ୍ତୁ"</string>
+ <!-- no translation found for accessibility_floating_button_action_remove_menu (6730432848162552135) -->
+ <skip />
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"ଟୋଗଲ୍ କରନ୍ତୁ"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"ଡିଭାଇସ୍ ନିୟନ୍ତ୍ରଣଗୁଡ଼ିକ"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"ନିୟନ୍ତ୍ରଣଗୁଡ଼ିକୁ ଯୋଗ କରିବାକୁ ଆପ୍ ବାଛନ୍ତୁ"</string>
@@ -933,6 +948,10 @@
<string name="mobile_data_settings_title" msgid="3955246641380064901">"ମୋବାଇଲ ଡାଟା"</string>
<string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"ସଂଯୋଗ କରାଯାଇଛି"</string>
+ <!-- no translation found for mobile_data_temp_connection_active (4590222725908806824) -->
+ <skip />
+ <!-- no translation found for mobile_data_poor_connection (819617772268371434) -->
+ <skip />
<string name="mobile_data_off_summary" msgid="3663995422004150567">"ମୋବାଇଲ ଡାଟା ସ୍ୱତଃ-ସଂଯୋଗ ହେବ ନାହିଁ"</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"ସଂଯୋଗ ନାହିଁ"</string>
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"ଅନ୍ୟ କୌଣସି ନେଟୱାର୍କ ଉପଲବ୍ଧ ନାହିଁ"</string>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index 992ffd6..fce69ec 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -248,7 +248,8 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"ਚਮਕ"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"ਰੰਗ ਪਲਟਨਾ"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"ਰੰਗ ਸੁਧਾਈ"</string>
- <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"ਵਰਤੋਂਕਾਰ ਸੈਟਿੰਗਾਂ"</string>
+ <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) -->
+ <skip />
<string name="quick_settings_done" msgid="2163641301648855793">"ਹੋ ਗਿਆ"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"ਬੰਦ ਕਰੋ"</string>
<string name="quick_settings_connected" msgid="3873605509184830379">"ਕਨੈਕਟ ਕੀਤਾ"</string>
@@ -727,6 +728,14 @@
<string name="mobile_data_disable_title" msgid="5366476131671617790">"ਕੀ ਮੋਬਾਈਲ ਡਾਟਾ ਬੰਦ ਕਰਨਾ ਹੈ?"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"ਤੁਸੀਂ <xliff:g id="CARRIER">%s</xliff:g> ਰਾਹੀਂ ਡਾਟੇ ਜਾਂ ਇੰਟਰਨੈੱਟ ਤੱਕ ਪਹੁੰਚ ਨਹੀਂ ਕਰ ਸਕੋਗੇ। ਇੰਟਰਨੈੱਟ ਸਿਰਫ਼ ਵਾਈ-ਫਾਈ ਰਾਹੀਂ ਉਪਲਬਧ ਹੋਵੇਗਾ।"</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"ਤੁਹਾਡਾ ਕੈਰੀਅਰ"</string>
+ <!-- no translation found for auto_data_switch_disable_title (5146527155665190652) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_disable_message (5885533647399535852) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_negative_button (2370876875999891444) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_positive_button (8531782041263087564) -->
+ <skip />
<string name="touch_filtered_warning" msgid="8119511393338714836">"ਕਿਸੇ ਐਪ ਵੱਲੋਂ ਇਜਾਜ਼ਤ ਬੇਨਤੀ ਨੂੰ ਢਕੇ ਜਾਣ ਕਾਰਨ ਸੈਟਿੰਗਾਂ ਤੁਹਾਡੇ ਜਵਾਬ ਦੀ ਪੁਸ਼ਟੀ ਨਹੀਂ ਕਰ ਸਕਦੀਆਂ।"</string>
<string name="slice_permission_title" msgid="3262615140094151017">"ਕੀ <xliff:g id="APP_0">%1$s</xliff:g> ਨੂੰ <xliff:g id="APP_2">%2$s</xliff:g> ਦੇ ਹਿੱਸੇ ਦਿਖਾਉਣ ਦੇਣੇ ਹਨ?"</string>
<string name="slice_permission_text_1" msgid="6675965177075443714">"- ਇਹ <xliff:g id="APP">%1$s</xliff:g> ਵਿੱਚੋਂ ਜਾਣਕਾਰੀ ਪੜ੍ਹ ਸਕਦਾ ਹੈ"</string>
@@ -785,12 +794,18 @@
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"ਵੱਡਦਰਸ਼ੀ ਵਿੰਡੋ ਸੈਟਿੰਗਾਂ"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"ਪਹੁੰਚਯੋਗਤਾ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਖੋਲ੍ਹਣ ਲਈ ਟੈਪ ਕਰੋ। ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਇਹ ਬਟਨ ਵਿਉਂਤਬੱਧ ਕਰੋ ਜਾਂ ਬਦਲੋ।\n\n"<annotation id="link">"ਸੈਟਿੰਗਾਂ ਦੇਖੋ"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"ਬਟਨ ਨੂੰ ਅਸਥਾਈ ਤੌਰ \'ਤੇ ਲੁਕਾਉਣ ਲਈ ਕਿਨਾਰੇ \'ਤੇ ਲਿਜਾਓ"</string>
+ <!-- no translation found for accessibility_floating_button_undo (511112888715708241) -->
+ <skip />
+ <!-- no translation found for accessibility_floating_button_undo_message_text (3044079592757099698) -->
+ <skip />
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"ਉੱਪਰ ਵੱਲ ਖੱਬੇ ਲਿਜਾਓ"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"ਉੱਪਰ ਵੱਲ ਸੱਜੇ ਲਿਜਾਓ"</string>
<string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"ਹੇਠਾਂ ਵੱਲ ਖੱਬੇ ਲਿਜਾਓ"</string>
<string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"ਹੇਠਾਂ ਵੱਲ ਸੱਜੇ ਲਿਜਾਓ"</string>
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"ਕਿਨਾਰੇ ਵਿੱਚ ਲਿਜਾ ਕੇ ਲੁਕਾਓ"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"ਕਿਨਾਰੇ ਤੋਂ ਬਾਹਰ ਕੱਢ ਕੇ ਦਿਖਾਓ"</string>
+ <!-- no translation found for accessibility_floating_button_action_remove_menu (6730432848162552135) -->
+ <skip />
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"ਟੌਗਲ ਕਰੋ"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"ਡੀਵਾਈਸ ਕੰਟਰੋਲ"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"ਕੰਟਰੋਲ ਸ਼ਾਮਲ ਕਰਨ ਲਈ ਐਪ ਚੁਣੋ"</string>
@@ -933,6 +948,10 @@
<string name="mobile_data_settings_title" msgid="3955246641380064901">"ਮੋਬਾਈਲ ਡਾਟਾ"</string>
<string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"ਕਨੈਕਟ ਹੈ"</string>
+ <!-- no translation found for mobile_data_temp_connection_active (4590222725908806824) -->
+ <skip />
+ <!-- no translation found for mobile_data_poor_connection (819617772268371434) -->
+ <skip />
<string name="mobile_data_off_summary" msgid="3663995422004150567">"ਮੋਬਾਈਲ ਡਾਟਾ ਸਵੈ-ਕਨੈਕਟ ਨਹੀਂ ਹੋਵੇਗਾ"</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"ਕੋਈ ਕਨੈਕਸ਼ਨ ਨਹੀਂ"</string>
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"ਕੋਈ ਹੋਰ ਨੈੱਟਵਰਕ ਉਪਲਬਧ ਨਹੀਂ ਹੈ"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index b706359..8787f36 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -248,7 +248,8 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Jasność"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Odwrócenie kolorów"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Korekcja kolorów"</string>
- <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Ustawienia użytkownika"</string>
+ <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) -->
+ <skip />
<string name="quick_settings_done" msgid="2163641301648855793">"Gotowe"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Zamknij"</string>
<string name="quick_settings_connected" msgid="3873605509184830379">"Połączono"</string>
@@ -727,6 +728,14 @@
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Wyłączyć mobilną transmisję danych?"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"Nie będziesz mieć dostępu do transmisji danych ani internetu w <xliff:g id="CARRIER">%s</xliff:g>. Internet będzie dostępny tylko przez Wi‑Fi."</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"Twój operator"</string>
+ <!-- no translation found for auto_data_switch_disable_title (5146527155665190652) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_disable_message (5885533647399535852) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_negative_button (2370876875999891444) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_positive_button (8531782041263087564) -->
+ <skip />
<string name="touch_filtered_warning" msgid="8119511393338714836">"Aplikacja Ustawienia nie może zweryfikować Twojej odpowiedzi, ponieważ inna aplikacja zasłania prośbę o udzielenie uprawnień."</string>
<string name="slice_permission_title" msgid="3262615140094151017">"Zezwolić aplikacji <xliff:g id="APP_0">%1$s</xliff:g> na pokazywanie wycinków z aplikacji <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
<string name="slice_permission_text_1" msgid="6675965177075443714">"- Może odczytywać informacje z aplikacji <xliff:g id="APP">%1$s</xliff:g>"</string>
@@ -785,12 +794,18 @@
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Ustawienia okna powiększania"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Kliknij, aby otworzyć ułatwienia dostępu. Dostosuj lub zmień ten przycisk w Ustawieniach.\n\n"<annotation id="link">"Wyświetl ustawienia"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Przesuń przycisk do krawędzi, aby ukryć go tymczasowo"</string>
+ <!-- no translation found for accessibility_floating_button_undo (511112888715708241) -->
+ <skip />
+ <!-- no translation found for accessibility_floating_button_undo_message_text (3044079592757099698) -->
+ <skip />
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Przenieś w lewy górny róg"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Przenieś w prawy górny róg"</string>
<string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Przenieś w lewy dolny róg"</string>
<string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Przenieś w prawy dolny róg"</string>
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Przenieś do krawędzi i ukryj"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Przenieś poza krawędź i pokaż"</string>
+ <!-- no translation found for accessibility_floating_button_action_remove_menu (6730432848162552135) -->
+ <skip />
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"przełącz"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Sterowanie urządzeniami"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Wybierz aplikację, do której chcesz dodać elementy sterujące"</string>
@@ -933,6 +948,10 @@
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobilna transmisja danych"</string>
<string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Połączono"</string>
+ <!-- no translation found for mobile_data_temp_connection_active (4590222725908806824) -->
+ <skip />
+ <!-- no translation found for mobile_data_poor_connection (819617772268371434) -->
+ <skip />
<string name="mobile_data_off_summary" msgid="3663995422004150567">"Mobilna transmisja danych nie połączy się automatycznie"</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"Brak połączenia"</string>
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"Brak innych dostępnych sieci"</string>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 78a6409..e6f0580 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -248,7 +248,8 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Brilho"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Inversão de cores"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Correção de cor"</string>
- <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Config. do usuário"</string>
+ <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) -->
+ <skip />
<string name="quick_settings_done" msgid="2163641301648855793">"Concluído"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Fechar"</string>
<string name="quick_settings_connected" msgid="3873605509184830379">"Conectado"</string>
@@ -727,6 +728,14 @@
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Desativar os dados móveis?"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"Você não terá acesso a dados ou à Internet pela operadora <xliff:g id="CARRIER">%s</xliff:g>. A Internet só estará disponível via Wi-Fi."</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"sua operadora"</string>
+ <!-- no translation found for auto_data_switch_disable_title (5146527155665190652) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_disable_message (5885533647399535852) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_negative_button (2370876875999891444) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_positive_button (8531782041263087564) -->
+ <skip />
<string name="touch_filtered_warning" msgid="8119511393338714836">"Como um app está ocultando uma solicitação de permissão, as configurações não podem verificar sua resposta."</string>
<string name="slice_permission_title" msgid="3262615140094151017">"Permitir que <xliff:g id="APP_0">%1$s</xliff:g> mostre partes do app <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
<string name="slice_permission_text_1" msgid="6675965177075443714">"- Pode ler informações do app <xliff:g id="APP">%1$s</xliff:g>"</string>
@@ -785,12 +794,18 @@
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Configurações da janela de lupa"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Toque para abrir os recursos de acessibilidade. Personalize ou substitua o botão nas Configurações.\n\n"<annotation id="link">"Ver configurações"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Mova o botão para a borda para ocultá-lo temporariamente"</string>
+ <!-- no translation found for accessibility_floating_button_undo (511112888715708241) -->
+ <skip />
+ <!-- no translation found for accessibility_floating_button_undo_message_text (3044079592757099698) -->
+ <skip />
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Mover para o canto superior esquerdo"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Mover para o canto superior direito"</string>
<string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Mover para o canto inferior esquerdo"</string>
<string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Mover para o canto inferior direito"</string>
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Mover para a borda e ocultar"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Mover para fora da borda e exibir"</string>
+ <!-- no translation found for accessibility_floating_button_action_remove_menu (6730432848162552135) -->
+ <skip />
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"alternar"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Controles do dispositivo"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Escolha um app para adicionar controles"</string>
@@ -933,6 +948,10 @@
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Dados móveis"</string>
<string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Conectado"</string>
+ <!-- no translation found for mobile_data_temp_connection_active (4590222725908806824) -->
+ <skip />
+ <!-- no translation found for mobile_data_poor_connection (819617772268371434) -->
+ <skip />
<string name="mobile_data_off_summary" msgid="3663995422004150567">"Sem conexão automática com dados móveis"</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"Sem conexão"</string>
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"Nenhuma outra rede disponível"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 30233b3..6c07ce0 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -248,7 +248,7 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Brilho"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Inversão de cores"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Correção da cor"</string>
- <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Definições do utilizador"</string>
+ <string name="quick_settings_more_user_settings" msgid="7634653308485206306">"Gerir utilizadores"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Concluído"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Fechar"</string>
<string name="quick_settings_connected" msgid="3873605509184830379">"Ligado"</string>
@@ -727,6 +727,14 @@
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Desativar os dados móveis?"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"Não terá acesso a dados ou à Internet através do operador <xliff:g id="CARRIER">%s</xliff:g>. A Internet estará disponível apenas por Wi-Fi."</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"o seu operador"</string>
+ <!-- no translation found for auto_data_switch_disable_title (5146527155665190652) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_disable_message (5885533647399535852) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_negative_button (2370876875999891444) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_positive_button (8531782041263087564) -->
+ <skip />
<string name="touch_filtered_warning" msgid="8119511393338714836">"Uma vez que uma app está a ocultar um pedido de autorização, as Definições não conseguem validar a sua resposta."</string>
<string name="slice_permission_title" msgid="3262615140094151017">"Permitir que a app <xliff:g id="APP_0">%1$s</xliff:g> mostre partes da app <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
<string name="slice_permission_text_1" msgid="6675965177075443714">"- Pode ler informações da app <xliff:g id="APP">%1$s</xliff:g>"</string>
@@ -785,12 +793,18 @@
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Definições da janela da lupa"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Toque para abrir funcionalidades de acessibilidade. Personal. ou substitua botão em Defin.\n\n"<annotation id="link">"Ver defin."</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Mova o botão para a extremidade para o ocultar temporariamente"</string>
+ <!-- no translation found for accessibility_floating_button_undo (511112888715708241) -->
+ <skip />
+ <!-- no translation found for accessibility_floating_button_undo_message_text (3044079592757099698) -->
+ <skip />
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Mover p/ parte sup. esquerda"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Mover parte superior direita"</string>
<string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Mover p/ parte infer. esquerda"</string>
<string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Mover parte inferior direita"</string>
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Mover p/ extremidade e ocultar"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Retirar extremidade e mostrar"</string>
+ <!-- no translation found for accessibility_floating_button_action_remove_menu (6730432848162552135) -->
+ <skip />
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"ativar/desativar"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Controlos de dispositivos"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Escolha uma app para adicionar controlos"</string>
@@ -933,6 +947,10 @@
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Dados móveis"</string>
<string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Ligado"</string>
+ <!-- no translation found for mobile_data_temp_connection_active (4590222725908806824) -->
+ <skip />
+ <!-- no translation found for mobile_data_poor_connection (819617772268371434) -->
+ <skip />
<string name="mobile_data_off_summary" msgid="3663995422004150567">"Sem ligação automática com dados móveis"</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"Sem ligação"</string>
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"Nenhuma outra rede disponível"</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 78a6409..e6f0580 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -248,7 +248,8 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Brilho"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Inversão de cores"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Correção de cor"</string>
- <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Config. do usuário"</string>
+ <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) -->
+ <skip />
<string name="quick_settings_done" msgid="2163641301648855793">"Concluído"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Fechar"</string>
<string name="quick_settings_connected" msgid="3873605509184830379">"Conectado"</string>
@@ -727,6 +728,14 @@
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Desativar os dados móveis?"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"Você não terá acesso a dados ou à Internet pela operadora <xliff:g id="CARRIER">%s</xliff:g>. A Internet só estará disponível via Wi-Fi."</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"sua operadora"</string>
+ <!-- no translation found for auto_data_switch_disable_title (5146527155665190652) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_disable_message (5885533647399535852) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_negative_button (2370876875999891444) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_positive_button (8531782041263087564) -->
+ <skip />
<string name="touch_filtered_warning" msgid="8119511393338714836">"Como um app está ocultando uma solicitação de permissão, as configurações não podem verificar sua resposta."</string>
<string name="slice_permission_title" msgid="3262615140094151017">"Permitir que <xliff:g id="APP_0">%1$s</xliff:g> mostre partes do app <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
<string name="slice_permission_text_1" msgid="6675965177075443714">"- Pode ler informações do app <xliff:g id="APP">%1$s</xliff:g>"</string>
@@ -785,12 +794,18 @@
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Configurações da janela de lupa"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Toque para abrir os recursos de acessibilidade. Personalize ou substitua o botão nas Configurações.\n\n"<annotation id="link">"Ver configurações"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Mova o botão para a borda para ocultá-lo temporariamente"</string>
+ <!-- no translation found for accessibility_floating_button_undo (511112888715708241) -->
+ <skip />
+ <!-- no translation found for accessibility_floating_button_undo_message_text (3044079592757099698) -->
+ <skip />
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Mover para o canto superior esquerdo"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Mover para o canto superior direito"</string>
<string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Mover para o canto inferior esquerdo"</string>
<string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Mover para o canto inferior direito"</string>
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Mover para a borda e ocultar"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Mover para fora da borda e exibir"</string>
+ <!-- no translation found for accessibility_floating_button_action_remove_menu (6730432848162552135) -->
+ <skip />
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"alternar"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Controles do dispositivo"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Escolha um app para adicionar controles"</string>
@@ -933,6 +948,10 @@
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Dados móveis"</string>
<string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Conectado"</string>
+ <!-- no translation found for mobile_data_temp_connection_active (4590222725908806824) -->
+ <skip />
+ <!-- no translation found for mobile_data_poor_connection (819617772268371434) -->
+ <skip />
<string name="mobile_data_off_summary" msgid="3663995422004150567">"Sem conexão automática com dados móveis"</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"Sem conexão"</string>
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"Nenhuma outra rede disponível"</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 0d96062..080edfd 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -248,7 +248,8 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Luminozitate"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Inversarea culorilor"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Corecția culorii"</string>
- <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Setări de utilizator"</string>
+ <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) -->
+ <skip />
<string name="quick_settings_done" msgid="2163641301648855793">"Terminat"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Închide"</string>
<string name="quick_settings_connected" msgid="3873605509184830379">"Conectat"</string>
@@ -727,6 +728,14 @@
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Dezactivezi datele mobile?"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"Nu vei avea acces la date sau la internet prin intermediul <xliff:g id="CARRIER">%s</xliff:g>. Internetul va fi disponibil numai prin Wi-Fi."</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"operatorul tău"</string>
+ <!-- no translation found for auto_data_switch_disable_title (5146527155665190652) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_disable_message (5885533647399535852) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_negative_button (2370876875999891444) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_positive_button (8531782041263087564) -->
+ <skip />
<string name="touch_filtered_warning" msgid="8119511393338714836">"Deoarece o aplicație acoperă o solicitare de permisiune, Setările nu îți pot verifica răspunsul."</string>
<string name="slice_permission_title" msgid="3262615140094151017">"Permiți ca <xliff:g id="APP_0">%1$s</xliff:g> să afișeze porțiuni din <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
<string name="slice_permission_text_1" msgid="6675965177075443714">"- Poate citi informații din <xliff:g id="APP">%1$s</xliff:g>"</string>
@@ -785,12 +794,18 @@
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Setările ferestrei de mărire"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Atinge ca să deschizi funcțiile de accesibilitate. Personalizează sau înlocuiește butonul în setări.\n\n"<annotation id="link">"Vezi setările"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Mută butonul spre margine pentru a-l ascunde temporar"</string>
+ <!-- no translation found for accessibility_floating_button_undo (511112888715708241) -->
+ <skip />
+ <!-- no translation found for accessibility_floating_button_undo_message_text (3044079592757099698) -->
+ <skip />
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Mută în stânga sus"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Mută în dreapta sus"</string>
<string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Mută în stânga jos"</string>
<string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Mută în dreapta jos"</string>
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Mută la margine și ascunde"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Mută de la margine și afișează"</string>
+ <!-- no translation found for accessibility_floating_button_action_remove_menu (6730432848162552135) -->
+ <skip />
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"Activează / dezactivează"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Comenzile dispozitivelor"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Alege aplicația pentru a adăuga comenzi"</string>
@@ -933,6 +948,10 @@
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Date mobile"</string>
<string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Conectat"</string>
+ <!-- no translation found for mobile_data_temp_connection_active (4590222725908806824) -->
+ <skip />
+ <!-- no translation found for mobile_data_poor_connection (819617772268371434) -->
+ <skip />
<string name="mobile_data_off_summary" msgid="3663995422004150567">"Nu se conectează automat la date mobile"</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"Nicio conexiune"</string>
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"Nu sunt disponibile alte rețele"</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 3d13b2c..b42701e 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -248,7 +248,8 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Яркость"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Инверсия цветов"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Коррекция цвета"</string>
- <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Пользовательские настройки"</string>
+ <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) -->
+ <skip />
<string name="quick_settings_done" msgid="2163641301648855793">"Готово"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Закрыть"</string>
<string name="quick_settings_connected" msgid="3873605509184830379">"Подключено"</string>
@@ -727,6 +728,14 @@
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Отключить мобильный Интернет?"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"Вы не сможете передавать данные или выходить в Интернет через оператора \"<xliff:g id="CARRIER">%s</xliff:g>\". Интернет будет доступен только по сети Wi-Fi."</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"ваш оператор"</string>
+ <!-- no translation found for auto_data_switch_disable_title (5146527155665190652) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_disable_message (5885533647399535852) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_negative_button (2370876875999891444) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_positive_button (8531782041263087564) -->
+ <skip />
<string name="touch_filtered_warning" msgid="8119511393338714836">"Невозможно принять ваше согласие, поскольку запрос скрыт другим приложением."</string>
<string name="slice_permission_title" msgid="3262615140094151017">"Разрешить приложению \"<xliff:g id="APP_0">%1$s</xliff:g>\" показывать фрагменты приложения \"<xliff:g id="APP_2">%2$s</xliff:g>\"?"</string>
<string name="slice_permission_text_1" msgid="6675965177075443714">"– Ему станут доступны данные из приложения \"<xliff:g id="APP">%1$s</xliff:g>\"."</string>
@@ -785,12 +794,18 @@
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Настройка окна лупы"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Нажмите, чтобы открыть спец. возможности. Настройте или замените эту кнопку в настройках.\n\n"<annotation id="link">"Настройки"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Чтобы временно скрыть кнопку, переместите ее к краю экрана"</string>
+ <!-- no translation found for accessibility_floating_button_undo (511112888715708241) -->
+ <skip />
+ <!-- no translation found for accessibility_floating_button_undo_message_text (3044079592757099698) -->
+ <skip />
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Перенести в левый верхний угол"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Перенести в правый верхний угол"</string>
<string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Перенести в левый нижний угол"</string>
<string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Перенести в правый нижний угол"</string>
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Перенести к краю и скрыть"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Вернуть из-за края и показать"</string>
+ <!-- no translation found for accessibility_floating_button_action_remove_menu (6730432848162552135) -->
+ <skip />
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"включить или отключить"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Управление устройствами"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Чтобы добавить виджеты управления, выберите приложение"</string>
@@ -933,6 +948,10 @@
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Мобильный интернет"</string>
<string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Подключено"</string>
+ <!-- no translation found for mobile_data_temp_connection_active (4590222725908806824) -->
+ <skip />
+ <!-- no translation found for mobile_data_poor_connection (819617772268371434) -->
+ <skip />
<string name="mobile_data_off_summary" msgid="3663995422004150567">"Без автоподключения к мобильному интернету"</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"Нет подключения к интернету"</string>
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"Нет других доступных сетей"</string>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index 01be742..bd272c7 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -248,7 +248,8 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"දීප්තිමත් බව"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"වර්ණ අපවර්තනය"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"වර්ණ නිවැරදි කිරීම"</string>
- <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"පරිශීලක සැකසීම්"</string>
+ <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) -->
+ <skip />
<string name="quick_settings_done" msgid="2163641301648855793">"නිමයි"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"වසන්න"</string>
<string name="quick_settings_connected" msgid="3873605509184830379">"සම්බන්ධිත"</string>
@@ -727,6 +728,14 @@
<string name="mobile_data_disable_title" msgid="5366476131671617790">"ජංගම දත්ත ක්රියාවිරහිත කරන්නද?"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"ඔබට <xliff:g id="CARRIER">%s</xliff:g> හරහා දත්ත හෝ අන්තර්ජාලයට පිවිසීමේ හැකියාවක් නැත. අන්තර්ජාලය Wi-Fi හරහා පමණක් ලබා ගත හැකිය."</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"ඔබගේ වාහකය"</string>
+ <!-- no translation found for auto_data_switch_disable_title (5146527155665190652) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_disable_message (5885533647399535852) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_negative_button (2370876875999891444) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_positive_button (8531782041263087564) -->
+ <skip />
<string name="touch_filtered_warning" msgid="8119511393338714836">"යෙදුමක් අවසර ඉල්ලීමක් කරන නිසා, සැකසීම්වලට ඔබගේ ප්රතිචාරය සත්යාපනය කළ නොහැකිය."</string>
<string name="slice_permission_title" msgid="3262615140094151017">"<xliff:g id="APP_0">%1$s</xliff:g> හට කොටස් <xliff:g id="APP_2">%2$s</xliff:g>ක් පෙන්වීමට ඉඩ දෙන්නද?"</string>
<string name="slice_permission_text_1" msgid="6675965177075443714">"- එයට <xliff:g id="APP">%1$s</xliff:g> වෙතින් තොරතුරු කියවිය හැකිය"</string>
@@ -785,12 +794,18 @@
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"විශාලන කවුළු සැකසීම්"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"ප්රවේශ්යතා විශේෂාංග විවෘත කිරීමට තට්ටු කරන්න. සැකසීම් තුළ මෙම බොත්තම අභිරුචිකරණය හෝ ප්රතිස්ථාපනය කරන්න.\n\n"<annotation id="link">"සැකසීම් බලන්න"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"එය තාවකාලිකව සැඟවීමට බොත්තම දාරයට ගෙන යන්න"</string>
+ <!-- no translation found for accessibility_floating_button_undo (511112888715708241) -->
+ <skip />
+ <!-- no translation found for accessibility_floating_button_undo_message_text (3044079592757099698) -->
+ <skip />
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"ඉහළ වමට ගෙන යන්න"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"ඉහළ දකුණට ගෙන යන්න"</string>
<string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"පහළ වමට ගෙන යන්න"</string>
<string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"පහළ දකුණට ගෙන යන්න"</string>
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"මායිමට ගෙන යන්න සහ සඟවන්න"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"මායිමෙන් පිටට ගන්න සහ පෙන්වන්න"</string>
+ <!-- no translation found for accessibility_floating_button_action_remove_menu (6730432848162552135) -->
+ <skip />
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"ටොගල් කරන්න"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"උපාංග පාලන"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"පාලන එක් කිරීමට යෙදුම තෝරා ගන්න"</string>
@@ -933,6 +948,10 @@
<string name="mobile_data_settings_title" msgid="3955246641380064901">"ජංගම දත්ත"</string>
<string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"සම්බන්ධයි"</string>
+ <!-- no translation found for mobile_data_temp_connection_active (4590222725908806824) -->
+ <skip />
+ <!-- no translation found for mobile_data_poor_connection (819617772268371434) -->
+ <skip />
<string name="mobile_data_off_summary" msgid="3663995422004150567">"ජංගම දත්ත ස්වංක්රියව සම්බන්ධ නොවනු ඇත"</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"සම්බන්ධතාවයක් නැත"</string>
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"ලබා ගත හැකි වෙනත් ජාල නැත"</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 76dce74..a0dd3c3 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -248,7 +248,8 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Jas"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Inverzia farieb"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Úprava farieb"</string>
- <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Používateľské nastavenia"</string>
+ <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) -->
+ <skip />
<string name="quick_settings_done" msgid="2163641301648855793">"Hotovo"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Zavrieť"</string>
<string name="quick_settings_connected" msgid="3873605509184830379">"Pripojené"</string>
@@ -727,6 +728,14 @@
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Chcete vypnúť mobilné dáta?"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"Nebudete mať prístup k dátam ani internetu prostredníctvom operátora <xliff:g id="CARRIER">%s</xliff:g>. Internet bude k dispozícii iba cez Wi‑Fi."</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"váš operátor"</string>
+ <!-- no translation found for auto_data_switch_disable_title (5146527155665190652) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_disable_message (5885533647399535852) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_negative_button (2370876875999891444) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_positive_button (8531782041263087564) -->
+ <skip />
<string name="touch_filtered_warning" msgid="8119511393338714836">"Nastavenia nemôžu overiť vašu odpoveď, pretože určitá aplikácia blokuje žiadosť o povolenie."</string>
<string name="slice_permission_title" msgid="3262615140094151017">"Povoliť aplikácii <xliff:g id="APP_0">%1$s</xliff:g> zobrazovať rezy z aplikácie <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
<string name="slice_permission_text_1" msgid="6675965177075443714">"– Môže čítať informácie z aplikácie <xliff:g id="APP">%1$s</xliff:g>"</string>
@@ -785,12 +794,18 @@
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Nastavenia okna lupy"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Funkcie dostupnosti otvoríte klepnutím. Tlačidlo prispôsobte alebo nahraďte v Nastav.\n\n"<annotation id="link">"Zobraz. nast."</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Ak chcete tlačidlo dočasne skryť, presuňte ho k okraju"</string>
+ <!-- no translation found for accessibility_floating_button_undo (511112888715708241) -->
+ <skip />
+ <!-- no translation found for accessibility_floating_button_undo_message_text (3044079592757099698) -->
+ <skip />
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Presunúť doľava nahor"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Presunúť doprava nahor"</string>
<string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Presunúť doľava nadol"</string>
<string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Presunúť doprava nadol"</string>
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Presunúť k okraju a skryť"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Presunúť z okraja a zobraziť"</string>
+ <!-- no translation found for accessibility_floating_button_action_remove_menu (6730432848162552135) -->
+ <skip />
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"prepínač"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Ovládanie zariadení"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Vyberte aplikáciu, ktorej ovládače si chcete pridať"</string>
@@ -933,6 +948,10 @@
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobilné dáta"</string>
<string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Pripojené"</string>
+ <!-- no translation found for mobile_data_temp_connection_active (4590222725908806824) -->
+ <skip />
+ <!-- no translation found for mobile_data_poor_connection (819617772268371434) -->
+ <skip />
<string name="mobile_data_off_summary" msgid="3663995422004150567">"Automatické pripojenie cez mobilné dáta nefunguje"</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"Bez pripojenia"</string>
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"Nie sú k dispozícii žiadne ďalšie siete"</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index cb306c2..44108c3 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -248,7 +248,8 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Svetlost"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Inverzija barv"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Popravljanje barv"</string>
- <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Uporabniške nastavitve"</string>
+ <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) -->
+ <skip />
<string name="quick_settings_done" msgid="2163641301648855793">"Končano"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Zapri"</string>
<string name="quick_settings_connected" msgid="3873605509184830379">"Povezava je vzpostavljena"</string>
@@ -727,6 +728,14 @@
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Želite izklopiti prenos podatkov v mobilnih omrežjih?"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"Prek operaterja »<xliff:g id="CARRIER">%s</xliff:g>« ne boste imeli dostopa do podatkovne povezave ali interneta. Internet bo na voljo samo prek povezave Wi-Fi."</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"svojega operaterja"</string>
+ <!-- no translation found for auto_data_switch_disable_title (5146527155665190652) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_disable_message (5885533647399535852) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_negative_button (2370876875999891444) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_positive_button (8531782041263087564) -->
+ <skip />
<string name="touch_filtered_warning" msgid="8119511393338714836">"Ker aplikacija zakriva zahtevo za dovoljenje, z nastavitvami ni mogoče preveriti vašega odziva."</string>
<string name="slice_permission_title" msgid="3262615140094151017">"Želite dovoliti, da aplikacija <xliff:g id="APP_0">%1$s</xliff:g> prikaže izreze aplikacije <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
<string name="slice_permission_text_1" msgid="6675965177075443714">"– lahko bere podatke v aplikaciji <xliff:g id="APP">%1$s</xliff:g>"</string>
@@ -785,12 +794,18 @@
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Nastavitve okna povečevalnika"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Dotaknite se za funkcije za ljudi s posebnimi potrebami. Ta gumb lahko prilagodite ali zamenjate v nastavitvah.\n\n"<annotation id="link">"Ogled nastavitev"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Če želite gumb začasno skriti, ga premaknite ob rob."</string>
+ <!-- no translation found for accessibility_floating_button_undo (511112888715708241) -->
+ <skip />
+ <!-- no translation found for accessibility_floating_button_undo_message_text (3044079592757099698) -->
+ <skip />
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Premakni zgoraj levo"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Premakni zgoraj desno"</string>
<string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Premakni spodaj levo"</string>
<string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Premakni spodaj desno"</string>
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Premakni na rob in skrij"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Premakni z roba in pokaži"</string>
+ <!-- no translation found for accessibility_floating_button_action_remove_menu (6730432848162552135) -->
+ <skip />
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"preklop"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Kontrolniki naprave"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Izberite aplikacijo za dodajanje kontrolnikov"</string>
@@ -933,6 +948,10 @@
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Prenos podatkov v mobilnem omrežju"</string>
<string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Povezano"</string>
+ <!-- no translation found for mobile_data_temp_connection_active (4590222725908806824) -->
+ <skip />
+ <!-- no translation found for mobile_data_poor_connection (819617772268371434) -->
+ <skip />
<string name="mobile_data_off_summary" msgid="3663995422004150567">"Mobilna podatkovna povezava ne bo samodejna."</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"Ni povezave"</string>
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"Nobeno drugo omrežje ni na voljo"</string>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index 9a6d73c..7630261 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -248,7 +248,8 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Ndriçimi"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Anasjellja e ngjyrës"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Korrigjimi i ngjyrës"</string>
- <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Cilësimet e përdoruesit"</string>
+ <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) -->
+ <skip />
<string name="quick_settings_done" msgid="2163641301648855793">"U krye"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Mbyll"</string>
<string name="quick_settings_connected" msgid="3873605509184830379">"I lidhur"</string>
@@ -727,6 +728,14 @@
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Të çaktivizohen të dhënat celulare?"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"Nuk do të kesh qasje te të dhënat ose interneti nëpërmjet <xliff:g id="CARRIER">%s</xliff:g>. Interneti do të ofrohet vetëm nëpërmjet Wi-Fi."</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"operatori yt celular"</string>
+ <!-- no translation found for auto_data_switch_disable_title (5146527155665190652) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_disable_message (5885533647399535852) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_negative_button (2370876875999891444) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_positive_button (8531782041263087564) -->
+ <skip />
<string name="touch_filtered_warning" msgid="8119511393338714836">"Duke qenë se një aplikacion po bllokon një kërkesë për leje, \"Cilësimet\" nuk mund të verifikojnë përgjigjen tënde."</string>
<string name="slice_permission_title" msgid="3262615140094151017">"Të lejohet <xliff:g id="APP_0">%1$s</xliff:g> që të shfaqë pjesë të <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
<string name="slice_permission_text_1" msgid="6675965177075443714">"- Mund të lexojë informacion nga <xliff:g id="APP">%1$s</xliff:g>"</string>
@@ -785,12 +794,18 @@
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Cilësimet e dritares së zmadhimit"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Trokit dhe hap veçoritë e qasshmërisë. Modifiko ose ndërro butonin te \"Cilësimet\".\n\n"<annotation id="link">"Shih cilësimet"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Zhvendose butonin në skaj për ta fshehur përkohësisht"</string>
+ <!-- no translation found for accessibility_floating_button_undo (511112888715708241) -->
+ <skip />
+ <!-- no translation found for accessibility_floating_button_undo_message_text (3044079592757099698) -->
+ <skip />
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Zhvendos lart majtas"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Zhvendos lart djathtas"</string>
<string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Zhvendos poshtë majtas"</string>
<string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Zhvendos poshtë djathtas"</string>
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Zhvendose te skaji dhe fshihe"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Zhvendose jashtë skajit dhe shfaqe"</string>
+ <!-- no translation found for accessibility_floating_button_action_remove_menu (6730432848162552135) -->
+ <skip />
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"aktivizo/çaktivizo"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Kontrollet e pajisjes"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Zgjidh aplikacionin për të shtuar kontrollet"</string>
@@ -933,6 +948,10 @@
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Të dhënat celulare"</string>
<string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Lidhur"</string>
+ <!-- no translation found for mobile_data_temp_connection_active (4590222725908806824) -->
+ <skip />
+ <!-- no translation found for mobile_data_poor_connection (819617772268371434) -->
+ <skip />
<string name="mobile_data_off_summary" msgid="3663995422004150567">"Të dhënat celulare nuk do të lidhen automatikisht"</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"Nuk ka lidhje"</string>
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"Nuk ofrohet asnjë rrjet tjetër"</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 0dff11f..2a7b88f 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -248,7 +248,8 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Осветљеност"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Инверзија боја"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Корекција боја"</string>
- <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Корисничка подешавања"</string>
+ <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) -->
+ <skip />
<string name="quick_settings_done" msgid="2163641301648855793">"Готово"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Затвори"</string>
<string name="quick_settings_connected" msgid="3873605509184830379">"Повезан"</string>
@@ -727,6 +728,14 @@
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Желите да искључите мобилне податке?"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"Нећете имати приступ подацима или интернету преко мобилног оператера <xliff:g id="CARRIER">%s</xliff:g>. Интернет ће бити доступан само преко WiFi везе."</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"мобилни оператер"</string>
+ <!-- no translation found for auto_data_switch_disable_title (5146527155665190652) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_disable_message (5885533647399535852) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_negative_button (2370876875999891444) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_positive_button (8531782041263087564) -->
+ <skip />
<string name="touch_filtered_warning" msgid="8119511393338714836">"Подешавања не могу да верификују ваш одговор јер апликација скрива захтев за дозволу."</string>
<string name="slice_permission_title" msgid="3262615140094151017">"Желите ли да дозволите апликацији <xliff:g id="APP_0">%1$s</xliff:g> да приказује исечке из апликације <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
<string name="slice_permission_text_1" msgid="6675965177075443714">"– Може да чита податке из апликације <xliff:g id="APP">%1$s</xliff:g>"</string>
@@ -785,12 +794,18 @@
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Подешавања прозора за увећање"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Додирните за функције приступачности. Прилагодите или замените ово дугме у Подешавањима.\n\n"<annotation id="link">"Подешавања"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Померите дугме до ивице да бисте га привремено сакрили"</string>
+ <!-- no translation found for accessibility_floating_button_undo (511112888715708241) -->
+ <skip />
+ <!-- no translation found for accessibility_floating_button_undo_message_text (3044079592757099698) -->
+ <skip />
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Премести горе лево"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Премести горе десно"</string>
<string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Премести доле лево"</string>
<string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Премести доле десно"</string>
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Премести до ивице и сакриј"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Премести изван ивице и прикажи"</string>
+ <!-- no translation found for accessibility_floating_button_action_remove_menu (6730432848162552135) -->
+ <skip />
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"укључите/искључите"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Контроле уређаја"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Одаберите апликацију за додавање контрола"</string>
@@ -933,6 +948,10 @@
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Мобилни подаци"</string>
<string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Повезано"</string>
+ <!-- no translation found for mobile_data_temp_connection_active (4590222725908806824) -->
+ <skip />
+ <!-- no translation found for mobile_data_poor_connection (819617772268371434) -->
+ <skip />
<string name="mobile_data_off_summary" msgid="3663995422004150567">"Није успело аутом. повезивање преко моб. података"</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"Веза није успостављена"</string>
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"Није доступна ниједна друга мрежа"</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index c1cdc5b..48654d5 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -248,7 +248,8 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Ljusstyrka"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Färginvertering"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Färgkorrigering"</string>
- <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Användarinställningar"</string>
+ <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) -->
+ <skip />
<string name="quick_settings_done" msgid="2163641301648855793">"Klart"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Stäng"</string>
<string name="quick_settings_connected" msgid="3873605509184830379">"Ansluten"</string>
@@ -727,6 +728,14 @@
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Vill du inaktivera mobildata?"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"Du kan inte skicka data eller använda internet via <xliff:g id="CARRIER">%s</xliff:g>. Internetanslutning blir bara möjlig via wifi."</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"din operatör"</string>
+ <!-- no translation found for auto_data_switch_disable_title (5146527155665190652) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_disable_message (5885533647399535852) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_negative_button (2370876875999891444) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_positive_button (8531782041263087564) -->
+ <skip />
<string name="touch_filtered_warning" msgid="8119511393338714836">"Svaret kan inte verifieras av Inställningar eftersom en app skymmer en begäran om behörighet."</string>
<string name="slice_permission_title" msgid="3262615140094151017">"Tillåter du att bitar av <xliff:g id="APP_2">%2$s</xliff:g> visas i <xliff:g id="APP_0">%1$s</xliff:g>?"</string>
<string name="slice_permission_text_1" msgid="6675965177075443714">"– Kan läsa information från <xliff:g id="APP">%1$s</xliff:g>"</string>
@@ -785,12 +794,18 @@
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Inställningar för förstoringsfönster"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Tryck för att öppna tillgänglighetsfunktioner. Anpassa/ersätt knappen i Inställningar.\n\n"<annotation id="link">"Inställningar"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Flytta knappen till kanten för att dölja den tillfälligt"</string>
+ <!-- no translation found for accessibility_floating_button_undo (511112888715708241) -->
+ <skip />
+ <!-- no translation found for accessibility_floating_button_undo_message_text (3044079592757099698) -->
+ <skip />
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Flytta högst upp till vänster"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Flytta högst upp till höger"</string>
<string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Flytta längst ned till vänster"</string>
<string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Flytta längst ned till höger"</string>
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Flytta till kanten och dölj"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Flytta från kanten och visa"</string>
+ <!-- no translation found for accessibility_floating_button_action_remove_menu (6730432848162552135) -->
+ <skip />
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"aktivera och inaktivera"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Enhetsstyrning"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Välj en app om du vill lägga till snabbkontroller"</string>
@@ -933,6 +948,10 @@
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobildata"</string>
<string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Ansluten"</string>
+ <!-- no translation found for mobile_data_temp_connection_active (4590222725908806824) -->
+ <skip />
+ <!-- no translation found for mobile_data_poor_connection (819617772268371434) -->
+ <skip />
<string name="mobile_data_off_summary" msgid="3663995422004150567">"Du ansluts inte till mobildata automatiskt"</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"Ingen anslutning"</string>
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"Inga andra nätverk är tillgängliga"</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 8ed824e..6bf2bc2 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -248,7 +248,8 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Ung\'avu"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Ugeuzaji rangi"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Usahihishaji wa rangirangi"</string>
- <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Mipangilio ya mtumiaji"</string>
+ <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) -->
+ <skip />
<string name="quick_settings_done" msgid="2163641301648855793">"Nimemaliza"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Funga"</string>
<string name="quick_settings_connected" msgid="3873605509184830379">"Imeunganishwa"</string>
@@ -727,6 +728,14 @@
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Ungependa kuzima data ya mtandao wa simu?"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"Hutaweza kufikia data au intaneti kupitia <xliff:g id="CARRIER">%s</xliff:g>. Intaneti itapatikana kupitia Wi-Fi pekee."</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"mtoa huduma wako"</string>
+ <!-- no translation found for auto_data_switch_disable_title (5146527155665190652) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_disable_message (5885533647399535852) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_negative_button (2370876875999891444) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_positive_button (8531782041263087564) -->
+ <skip />
<string name="touch_filtered_warning" msgid="8119511393338714836">"Kwa sababu programu nyingine inazuia ombi la ruhusa, hatuwezi kuthibitisha jibu lako katika Mipangilio."</string>
<string name="slice_permission_title" msgid="3262615140094151017">"Ungependa kuruhusu <xliff:g id="APP_0">%1$s</xliff:g> ionyeshe vipengee <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
<string name="slice_permission_text_1" msgid="6675965177075443714">"- Inaweza kusoma maelezo kutoka <xliff:g id="APP">%1$s</xliff:g>"</string>
@@ -785,12 +794,18 @@
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Mipangilio ya dirisha la kikuzaji"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Gusa ili ufungue vipengele vya ufikivu. Weka mapendeleo au ubadilishe kitufe katika Mipangilio.\n\n"<annotation id="link">"Angalia mipangilio"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Sogeza kitufe kwenye ukingo ili ukifiche kwa muda"</string>
+ <!-- no translation found for accessibility_floating_button_undo (511112888715708241) -->
+ <skip />
+ <!-- no translation found for accessibility_floating_button_undo_message_text (3044079592757099698) -->
+ <skip />
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Sogeza juu kushoto"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Sogeza juu kulia"</string>
<string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Sogeza chini kushoto"</string>
<string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Sogeza chini kulia"</string>
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Sogeza kwenye ukingo kisha ufiche"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Sogeza nje ya ukingo kisha uonyeshe"</string>
+ <!-- no translation found for accessibility_floating_button_action_remove_menu (6730432848162552135) -->
+ <skip />
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"geuza"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Vidhibiti vya vifaa"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Chagua programu ili uweke vidhibiti"</string>
@@ -933,6 +948,10 @@
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Data ya mtandao wa simu"</string>
<string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Imeunganishwa"</string>
+ <!-- no translation found for mobile_data_temp_connection_active (4590222725908806824) -->
+ <skip />
+ <!-- no translation found for mobile_data_poor_connection (819617772268371434) -->
+ <skip />
<string name="mobile_data_off_summary" msgid="3663995422004150567">"Data ya mtandao wa simu haitaunganishwa kiotomatiki"</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"Hakuna muunganisho"</string>
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"Hakuna mitandao mingine inayopatikana"</string>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index 9397b6c..b291004 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -248,7 +248,8 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"ஒளிர்வு"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"கலர் இன்வெர்ஷன்"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"கலர் கரெக்ஷன்"</string>
- <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"பயனர் அமைப்புகள்"</string>
+ <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) -->
+ <skip />
<string name="quick_settings_done" msgid="2163641301648855793">"முடிந்தது"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"மூடுக"</string>
<string name="quick_settings_connected" msgid="3873605509184830379">"இணைக்கப்பட்டது"</string>
@@ -727,6 +728,14 @@
<string name="mobile_data_disable_title" msgid="5366476131671617790">"மொபைல் டேட்டாவை ஆஃப் செய்யவா?"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"<xliff:g id="CARRIER">%s</xliff:g> மூலம் டேட்டா அல்லது இணையத்தை உங்களால் பயன்படுத்த முடியாது. வைஃபை வழியாக மட்டுமே இணையத்தைப் பயன்படுத்த முடியும்."</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"உங்கள் மொபைல் நிறுவனம்"</string>
+ <!-- no translation found for auto_data_switch_disable_title (5146527155665190652) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_disable_message (5885533647399535852) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_negative_button (2370876875999891444) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_positive_button (8531782041263087564) -->
+ <skip />
<string name="touch_filtered_warning" msgid="8119511393338714836">"அனுமதிக் கோரிக்கையை ஆப்ஸ் மறைப்பதால், அமைப்புகளால் உங்கள் பதிலைச் சரிபார்க்க முடியாது."</string>
<string name="slice_permission_title" msgid="3262615140094151017">"<xliff:g id="APP_0">%1$s</xliff:g> ஆப்ஸை, <xliff:g id="APP_2">%2$s</xliff:g> ஆப்ஸின் விழிப்பூட்டல்களைக் காண்பிக்க அனுமதிக்கவா?"</string>
<string name="slice_permission_text_1" msgid="6675965177075443714">"- இது, <xliff:g id="APP">%1$s</xliff:g> பயன்பாட்டிலிருந்து தகவலைப் படிக்கும்"</string>
@@ -785,12 +794,18 @@
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"சாளரத்தைப் பெரிதாக்கும் கருவிக்கான அமைப்புகள்"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"அணுகல்தன்மை அம்சத்தை திறக்க தட்டவும். அமைப்பில் பட்டனை பிரத்தியேகமாக்கலாம்/மாற்றலாம்.\n\n"<annotation id="link">"அமைப்பில் காண்க"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"பட்டனைத் தற்காலிகமாக மறைக்க ஓரத்திற்கு நகர்த்தும்"</string>
+ <!-- no translation found for accessibility_floating_button_undo (511112888715708241) -->
+ <skip />
+ <!-- no translation found for accessibility_floating_button_undo_message_text (3044079592757099698) -->
+ <skip />
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"மேலே இடதுபுறத்திற்கு நகர்த்து"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"மேலே வலதுபுறத்திற்கு நகர்த்து"</string>
<string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"கீழே இடதுபுறத்திற்கு நகர்த்து"</string>
<string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"கீழே வலதுபுறத்திற்கு நகர்த்து"</string>
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"ஓரத்திற்கு நகர்த்தி மறை"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"ஓரத்திற்கு நகர்த்தி, காட்டு"</string>
+ <!-- no translation found for accessibility_floating_button_action_remove_menu (6730432848162552135) -->
+ <skip />
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"நிலைமாற்று"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"சாதனக் கட்டுப்பாடுகள்"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"கட்டுப்பாடுகளைச் சேர்க்க வேண்டிய ஆப்ஸைத் தேர்ந்தெடுங்கள்"</string>
@@ -933,6 +948,10 @@
<string name="mobile_data_settings_title" msgid="3955246641380064901">"மொபைல் டேட்டா"</string>
<string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"இணைக்கப்பட்டது"</string>
+ <!-- no translation found for mobile_data_temp_connection_active (4590222725908806824) -->
+ <skip />
+ <!-- no translation found for mobile_data_poor_connection (819617772268371434) -->
+ <skip />
<string name="mobile_data_off_summary" msgid="3663995422004150567">"மொபைல் டேட்டாவுடன் தானாக இணைக்காது"</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"இணைப்பு இல்லை"</string>
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"வேறு நெட்வொர்க்குகள் எதுவும் கிடைக்கவில்லை"</string>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index f202fae..4c34f45 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -248,7 +248,8 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"ప్రకాశం"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"కలర్ మార్పిడి"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"కలర్ కరెక్షన్"</string>
- <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"యూజర్ సెట్టింగ్లు"</string>
+ <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) -->
+ <skip />
<string name="quick_settings_done" msgid="2163641301648855793">"పూర్తయింది"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"మూసివేయి"</string>
<string name="quick_settings_connected" msgid="3873605509184830379">"కనెక్ట్ చేయబడినది"</string>
@@ -727,6 +728,14 @@
<string name="mobile_data_disable_title" msgid="5366476131671617790">"మొబైల్ డేటాను ఆఫ్ చేయాలా?"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"\"<xliff:g id="CARRIER">%s</xliff:g>\" ద్వారా మీకు డేటా లేదా ఇంటర్నెట్కు యాక్సెస్ ఉండదు. Wi-Fi ద్వారా మాత్రమే ఇంటర్నెట్ అందుబాటులో ఉంటుంది."</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"మీ క్యారియర్"</string>
+ <!-- no translation found for auto_data_switch_disable_title (5146527155665190652) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_disable_message (5885533647399535852) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_negative_button (2370876875999891444) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_positive_button (8531782041263087564) -->
+ <skip />
<string name="touch_filtered_warning" msgid="8119511393338714836">"అనుమతి రిక్వెస్ట్కు ఒక యాప్ అడ్డు తగులుతున్నందున సెట్టింగ్లు మీ ప్రతిస్పందనను ధృవీకరించలేకపోయాయి."</string>
<string name="slice_permission_title" msgid="3262615140094151017">"<xliff:g id="APP_2">%2$s</xliff:g> స్లైస్లను చూపించడానికి <xliff:g id="APP_0">%1$s</xliff:g>ని అనుమతించండి?"</string>
<string name="slice_permission_text_1" msgid="6675965177075443714">"- ఇది <xliff:g id="APP">%1$s</xliff:g> నుండి సమాచారాన్ని చదువుతుంది"</string>
@@ -785,12 +794,18 @@
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"మాగ్నిఫయర్ విండో సెట్టింగ్లు"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"యాక్సెసిబిలిటీ ఫీచర్లను తెరవడానికి ట్యాప్ చేయండి. సెట్టింగ్లలో ఈ బటన్ను అనుకూలంగా మార్చండి లేదా రీప్లేస్ చేయండి.\n\n"<annotation id="link">"వీక్షణ సెట్టింగ్లు"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"తాత్కాలికంగా దానిని దాచడానికి బటన్ను చివరకు తరలించండి"</string>
+ <!-- no translation found for accessibility_floating_button_undo (511112888715708241) -->
+ <skip />
+ <!-- no translation found for accessibility_floating_button_undo_message_text (3044079592757099698) -->
+ <skip />
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"ఎగువ ఎడమ వైపునకు తరలించు"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"ఎగువ కుడి వైపునకు తరలించు"</string>
<string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"దిగువ ఎడమ వైపునకు తరలించు"</string>
<string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"దిగువ కుడి వైపునకు తరలించు"</string>
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"అంచుకు తరలించి దాచండి"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"అంచుని తరలించి చూపించు"</string>
+ <!-- no translation found for accessibility_floating_button_action_remove_menu (6730432848162552135) -->
+ <skip />
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"టోగుల్ చేయి"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"డివైజ్ కంట్రోల్స్"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"కంట్రోల్స్ను యాడ్ చేయడానికి యాప్ను ఎంచుకోండి"</string>
@@ -933,6 +948,10 @@
<string name="mobile_data_settings_title" msgid="3955246641380064901">"మొబైల్ డేటా"</string>
<string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"కనెక్ట్ చేయబడింది"</string>
+ <!-- no translation found for mobile_data_temp_connection_active (4590222725908806824) -->
+ <skip />
+ <!-- no translation found for mobile_data_poor_connection (819617772268371434) -->
+ <skip />
<string name="mobile_data_off_summary" msgid="3663995422004150567">"మొబైల్ డేటా ఆటోమెటిక్గా కనెక్ట్ అవ్వదు"</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"కనెక్షన్ లేదు"</string>
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"ఇతర నెట్వర్క్లేవీ అందుబాటులో లేవు"</string>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index f216437..5de908c 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -248,7 +248,7 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"ความสว่าง"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"การกลับสี"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"การแก้สี"</string>
- <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"การตั้งค่าผู้ใช้"</string>
+ <string name="quick_settings_more_user_settings" msgid="7634653308485206306">"จัดการผู้ใช้"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"เสร็จสิ้น"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"ปิด"</string>
<string name="quick_settings_connected" msgid="3873605509184830379">"เชื่อมต่อ"</string>
@@ -727,6 +727,14 @@
<string name="mobile_data_disable_title" msgid="5366476131671617790">"ปิดอินเทอร์เน็ตมือถือไหม"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"คุณจะใช้เน็ตมือถือหรืออินเทอร์เน็ตผ่าน \"<xliff:g id="CARRIER">%s</xliff:g>\" ไม่ได้ แต่จะใช้ผ่าน Wi-Fi ได้เท่านั้น"</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"ผู้ให้บริการของคุณ"</string>
+ <!-- no translation found for auto_data_switch_disable_title (5146527155665190652) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_disable_message (5885533647399535852) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_negative_button (2370876875999891444) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_positive_button (8531782041263087564) -->
+ <skip />
<string name="touch_filtered_warning" msgid="8119511393338714836">"เนื่องจากแอปหนึ่งได้บดบังคำขอสิทธิ์ ระบบจึงไม่สามารถยืนยันคำตอบของคุณสำหรับการตั้งค่าได้"</string>
<string name="slice_permission_title" msgid="3262615140094151017">"อนุญาตให้ <xliff:g id="APP_0">%1$s</xliff:g> แสดงส่วนต่างๆ ของ <xliff:g id="APP_2">%2$s</xliff:g>"</string>
<string name="slice_permission_text_1" msgid="6675965177075443714">"- อ่านข้อมูลจาก <xliff:g id="APP">%1$s</xliff:g> ได้"</string>
@@ -785,12 +793,18 @@
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"การตั้งค่าหน้าต่างแว่นขยาย"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"แตะเพื่อเปิดฟีเจอร์การช่วยเหลือพิเศษ ปรับแต่งหรือแทนที่ปุ่มนี้ในการตั้งค่า\n\n"<annotation id="link">"ดูการตั้งค่า"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"ย้ายปุ่มไปที่ขอบเพื่อซ่อนชั่วคราว"</string>
+ <!-- no translation found for accessibility_floating_button_undo (511112888715708241) -->
+ <skip />
+ <!-- no translation found for accessibility_floating_button_undo_message_text (3044079592757099698) -->
+ <skip />
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"ย้ายไปด้านซ้ายบน"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"ย้ายไปด้านขวาบน"</string>
<string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"ย้ายไปด้านซ้ายล่าง"</string>
<string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"ย้ายไปด้านขาวล่าง"</string>
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"ย้ายไปที่ขอบและซ่อน"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"ย้ายออกจากขอบและแสดง"</string>
+ <!-- no translation found for accessibility_floating_button_action_remove_menu (6730432848162552135) -->
+ <skip />
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"สลับ"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"ระบบควบคุมอุปกรณ์"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"เลือกแอปเพื่อเพิ่มตัวควบคุม"</string>
@@ -933,6 +947,10 @@
<string name="mobile_data_settings_title" msgid="3955246641380064901">"อินเทอร์เน็ตมือถือ"</string>
<string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"เชื่อมต่อแล้ว"</string>
+ <!-- no translation found for mobile_data_temp_connection_active (4590222725908806824) -->
+ <skip />
+ <!-- no translation found for mobile_data_poor_connection (819617772268371434) -->
+ <skip />
<string name="mobile_data_off_summary" msgid="3663995422004150567">"อินเทอร์เน็ตมือถือจะไม่เชื่อมต่ออัตโนมัติ"</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"ไม่มีการเชื่อมต่อ"</string>
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"ไม่มีเครือข่ายอื่นๆ ที่พร้อมใช้งาน"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index f1acf43..f47b906 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -248,7 +248,7 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Brightness"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Pag-invert ng kulay"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Pagtatama ng kulay"</string>
- <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Mga setting ng user"</string>
+ <string name="quick_settings_more_user_settings" msgid="7634653308485206306">"Pamahalaan ang mga user"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Tapos na"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Isara"</string>
<string name="quick_settings_connected" msgid="3873605509184830379">"Nakakonekta"</string>
@@ -727,6 +727,14 @@
<string name="mobile_data_disable_title" msgid="5366476131671617790">"I-off ang mobile data?"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"Hindi ka magkaka-access sa data o internet sa pamamagitan ng <xliff:g id="CARRIER">%s</xliff:g>. Available lang ang internet sa pamamagitan ng Wi-Fi."</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"ang iyong carrier"</string>
+ <!-- no translation found for auto_data_switch_disable_title (5146527155665190652) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_disable_message (5885533647399535852) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_negative_button (2370876875999891444) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_positive_button (8531782041263087564) -->
+ <skip />
<string name="touch_filtered_warning" msgid="8119511393338714836">"Hindi ma-verify ng Mga Setting ang iyong tugon dahil may app na tumatakip sa isang kahilingan sa pagpapahintulot."</string>
<string name="slice_permission_title" msgid="3262615140094151017">"Payagan ang <xliff:g id="APP_0">%1$s</xliff:g> na ipakita ang mga slice ng <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
<string name="slice_permission_text_1" msgid="6675965177075443714">"- Nakakabasa ito ng impormasyon mula sa <xliff:g id="APP">%1$s</xliff:g>"</string>
@@ -785,12 +793,18 @@
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Mga setting ng window ng magnifier"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"I-tap, buksan mga feature ng accessibility. I-customize o palitan button sa Mga Setting.\n\n"<annotation id="link">"Tingnan ang mga setting"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Ilipat ang button sa gilid para pansamantala itong itago"</string>
+ <!-- no translation found for accessibility_floating_button_undo (511112888715708241) -->
+ <skip />
+ <!-- no translation found for accessibility_floating_button_undo_message_text (3044079592757099698) -->
+ <skip />
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Ilipat sa kaliwa sa itaas"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Ilipat sa kanan sa itaas"</string>
<string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Ilipat sa kaliwa sa ibaba"</string>
<string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Ilipat sa kanan sa ibaba"</string>
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Ilipat sa sulok at itago"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Alisin sa sulok at ipakita"</string>
+ <!-- no translation found for accessibility_floating_button_action_remove_menu (6730432848162552135) -->
+ <skip />
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"i-toggle"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Mga kontrol ng device"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Pumili ng app para magdagdag ng mga kontrol"</string>
@@ -933,6 +947,10 @@
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobile data"</string>
<string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Nakakonekta"</string>
+ <!-- no translation found for mobile_data_temp_connection_active (4590222725908806824) -->
+ <skip />
+ <!-- no translation found for mobile_data_poor_connection (819617772268371434) -->
+ <skip />
<string name="mobile_data_off_summary" msgid="3663995422004150567">"Hindi awtomatikong kokonekta ang mobile data"</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"Walang koneksyon"</string>
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"Walang available na iba pang network"</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 7b52a41..17dfa48 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -248,7 +248,8 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Parlaklık"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Rengi ters çevirme"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Renk düzeltme"</string>
- <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Kullanıcı ayarları"</string>
+ <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) -->
+ <skip />
<string name="quick_settings_done" msgid="2163641301648855793">"Bitti"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Kapat"</string>
<string name="quick_settings_connected" msgid="3873605509184830379">"Bağlı"</string>
@@ -727,6 +728,14 @@
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Mobil veri kapatılsın mı?"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"<xliff:g id="CARRIER">%s</xliff:g> üzerinden veri veya internet erişiminiz olmayacak. İnternet yalnızca kablosuz bağlantı üzerinden kullanılabilecek."</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"operatörünüz"</string>
+ <!-- no translation found for auto_data_switch_disable_title (5146527155665190652) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_disable_message (5885533647399535852) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_negative_button (2370876875999891444) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_positive_button (8531782041263087564) -->
+ <skip />
<string name="touch_filtered_warning" msgid="8119511393338714836">"Bir uygulama bir izin isteğinin anlaşılmasını engellediğinden, Ayarlar, yanıtınızı doğrulayamıyor."</string>
<string name="slice_permission_title" msgid="3262615140094151017">"<xliff:g id="APP_0">%1$s</xliff:g> uygulamasının, <xliff:g id="APP_2">%2$s</xliff:g> dilimlerini göstermesine izin verilsin mi?"</string>
<string name="slice_permission_text_1" msgid="6675965177075443714">"- <xliff:g id="APP">%1$s</xliff:g> uygulamasından bilgileri okuyabilir"</string>
@@ -785,12 +794,18 @@
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Büyüteç penceresi ayarları"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Erişilebilirlik özelliklerini açmak için dokunun. Bu düğmeyi Ayarlar\'dan özelleştirin veya değiştirin.\n\n"<annotation id="link">"Ayarları göster"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Düğmeyi geçici olarak gizlemek için kenara taşıyın"</string>
+ <!-- no translation found for accessibility_floating_button_undo (511112888715708241) -->
+ <skip />
+ <!-- no translation found for accessibility_floating_button_undo_message_text (3044079592757099698) -->
+ <skip />
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Sol üste taşı"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Sağ üste taşı"</string>
<string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Sol alta taşı"</string>
<string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Sağ alta taşı"</string>
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Kenara taşıyıp gizle"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Kenarın dışına taşıyıp göster"</string>
+ <!-- no translation found for accessibility_floating_button_action_remove_menu (6730432848162552135) -->
+ <skip />
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"değiştir"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Cihaz denetimleri"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Denetim eklemek için uygulama seçin"</string>
@@ -933,6 +948,10 @@
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobil veri"</string>
<string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Bağlı"</string>
+ <!-- no translation found for mobile_data_temp_connection_active (4590222725908806824) -->
+ <skip />
+ <!-- no translation found for mobile_data_poor_connection (819617772268371434) -->
+ <skip />
<string name="mobile_data_off_summary" msgid="3663995422004150567">"Mobil veri otomatik olarak bağlanmıyor"</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"Bağlantı yok"</string>
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"Kullanılabilir başka ağ yok"</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 6bd9e30..ff1b594 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -248,7 +248,8 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Яскравість"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Інверсія кольорів"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Корекція кольору"</string>
- <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Налаштування користувача"</string>
+ <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) -->
+ <skip />
<string name="quick_settings_done" msgid="2163641301648855793">"Готово"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Закрити"</string>
<string name="quick_settings_connected" msgid="3873605509184830379">"Під’єднано"</string>
@@ -727,6 +728,14 @@
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Вимкнути мобільний Інтернет?"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"Ви не матимете доступу до даних чи Інтернету через оператора <xliff:g id="CARRIER">%s</xliff:g>. Інтернет буде доступний лише через Wi-Fi."</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"ваш оператор"</string>
+ <!-- no translation found for auto_data_switch_disable_title (5146527155665190652) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_disable_message (5885533647399535852) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_negative_button (2370876875999891444) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_positive_button (8531782041263087564) -->
+ <skip />
<string name="touch_filtered_warning" msgid="8119511393338714836">"Не вдається підтвердити вашу відповідь у налаштуваннях, оскільки інший додаток заступає запит на дозвіл."</string>
<string name="slice_permission_title" msgid="3262615140094151017">"Дозволити додатку <xliff:g id="APP_0">%1$s</xliff:g> показувати фрагменти додатка <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
<string name="slice_permission_text_1" msgid="6675965177075443714">"- Має доступ до інформації з додатка <xliff:g id="APP">%1$s</xliff:g>"</string>
@@ -785,12 +794,18 @@
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Налаштування розміру лупи"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Кнопка спеціальних можливостей. Змініть або замініть її в Налаштуваннях.\n\n"<annotation id="link">"Переглянути налаштування"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Щоб тимчасово сховати кнопку, перемістіть її на край екрана"</string>
+ <!-- no translation found for accessibility_floating_button_undo (511112888715708241) -->
+ <skip />
+ <!-- no translation found for accessibility_floating_button_undo_message_text (3044079592757099698) -->
+ <skip />
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Перемістити ліворуч угору"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Перемістити праворуч угору"</string>
<string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Перемістити ліворуч униз"</string>
<string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Перемістити праворуч униз"</string>
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Перемістити до краю, приховати"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Перемістити від краю, показати"</string>
+ <!-- no translation found for accessibility_floating_button_action_remove_menu (6730432848162552135) -->
+ <skip />
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"перемкнути"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Керування пристроями"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Виберіть, для якого додатка налаштувати елементи керування"</string>
@@ -933,6 +948,10 @@
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Мобільний трафік"</string>
<string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Підключено"</string>
+ <!-- no translation found for mobile_data_temp_connection_active (4590222725908806824) -->
+ <skip />
+ <!-- no translation found for mobile_data_poor_connection (819617772268371434) -->
+ <skip />
<string name="mobile_data_off_summary" msgid="3663995422004150567">"Мобільний Інтернет не підключатиметься автоматично"</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"Немає з\'єднання"</string>
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"Інші мережі недоступні"</string>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index ec382b2..10e0e68 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -248,7 +248,8 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"چمکیلا پن"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"رنگوں کی تقلیب"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"رنگ کی اصلاح"</string>
- <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"صارف کی ترتیبات"</string>
+ <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) -->
+ <skip />
<string name="quick_settings_done" msgid="2163641301648855793">"ہو گیا"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"بند کریں"</string>
<string name="quick_settings_connected" msgid="3873605509184830379">"مربوط"</string>
@@ -727,6 +728,14 @@
<string name="mobile_data_disable_title" msgid="5366476131671617790">"موبائل ڈیٹا آف کریں؟"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"آپ کو <xliff:g id="CARRIER">%s</xliff:g> کے ذریعے ڈیٹا یا انٹرنیٹ تک رسائی حاصل نہیں ہوگی۔ انٹرنیٹ صرف Wi-Fi کے ذریعے دستیاب ہوگا۔"</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"آپ کا کریئر"</string>
+ <!-- no translation found for auto_data_switch_disable_title (5146527155665190652) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_disable_message (5885533647399535852) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_negative_button (2370876875999891444) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_positive_button (8531782041263087564) -->
+ <skip />
<string name="touch_filtered_warning" msgid="8119511393338714836">"چونکہ ایک ایپ اجازت کی درخواست کو مبہم کر رہی ہے، لہذا ترتیبات آپ کے جواب کی توثیق نہیں کر سکتی ہیں۔"</string>
<string name="slice_permission_title" msgid="3262615140094151017">"<xliff:g id="APP_0">%1$s</xliff:g> کو <xliff:g id="APP_2">%2$s</xliff:g> کے سلائسز دکھانے کی اجازت دیں؟"</string>
<string name="slice_permission_text_1" msgid="6675965177075443714">"- یہ <xliff:g id="APP">%1$s</xliff:g> کی معلومات پڑھ سکتا ہے"</string>
@@ -785,12 +794,18 @@
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"میگنیفائر ونڈو کی ترتیبات"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"ایکسیسبیلٹی خصوصیات کھولنے کے لیے تھپتھپائیں۔ ترتیبات میں اس بٹن کو حسب ضرورت بنائیں یا تبدیل کریں۔\n\n"<annotation id="link">"ترتیبات ملاحظہ کریں"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"عارضی طور پر بٹن کو چھپانے کے لئے اسے کنارے پر لے جائیں"</string>
+ <!-- no translation found for accessibility_floating_button_undo (511112888715708241) -->
+ <skip />
+ <!-- no translation found for accessibility_floating_button_undo_message_text (3044079592757099698) -->
+ <skip />
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"اوپر بائیں جانب لے جائیں"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"اوپر دائیں جانب لے جائيں"</string>
<string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"نیچے بائیں جانب لے جائیں"</string>
<string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"نیچے دائیں جانب لے جائیں"</string>
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"EDGE پر لے جائیں اور چھپائیں"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"EDGE اور شو سے باہر منتقل کریں"</string>
+ <!-- no translation found for accessibility_floating_button_action_remove_menu (6730432848162552135) -->
+ <skip />
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"ٹوگل کریں"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"آلہ کے کنٹرولز"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"کنٹرولز شامل کرنے کے لیے ایپ منتخب کریں"</string>
@@ -933,6 +948,10 @@
<string name="mobile_data_settings_title" msgid="3955246641380064901">"موبائل ڈیٹا"</string>
<string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="NETWORKMODE">%2$s</xliff:g> / <xliff:g id="STATE">%1$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"منسلک ہے"</string>
+ <!-- no translation found for mobile_data_temp_connection_active (4590222725908806824) -->
+ <skip />
+ <!-- no translation found for mobile_data_poor_connection (819617772268371434) -->
+ <skip />
<string name="mobile_data_off_summary" msgid="3663995422004150567">"موبائل ڈیٹا خودکار طور پر منسلک نہیں ہوگا"</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"کوئی کنکشن نہیں"</string>
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"کوئی دوسرا نیٹ ورک دستیاب نہیں ہے"</string>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index a666432..184044d 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -248,7 +248,8 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Yorqinlik"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Ranglarni akslantirish"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Ranglarni tuzatish"</string>
- <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Foydalanuvchi sozlamalari"</string>
+ <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) -->
+ <skip />
<string name="quick_settings_done" msgid="2163641301648855793">"Tayyor"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Yopish"</string>
<string name="quick_settings_connected" msgid="3873605509184830379">"Ulangan"</string>
@@ -727,6 +728,14 @@
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Mobil internet uzilsinmi?"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"<xliff:g id="CARRIER">%s</xliff:g> orqali internetdan foydalana olmaysiz. Internet faqat Wi-Fi orqali ishlaydi."</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"aloqa operatoringiz"</string>
+ <!-- no translation found for auto_data_switch_disable_title (5146527155665190652) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_disable_message (5885533647399535852) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_negative_button (2370876875999891444) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_positive_button (8531782041263087564) -->
+ <skip />
<string name="touch_filtered_warning" msgid="8119511393338714836">"Ilova ruxsatnoma so‘roviga xalaqit qilayotgani tufayli, “Sozlamalar” ilovasi javobingizni tekshira olmaydi."</string>
<string name="slice_permission_title" msgid="3262615140094151017">"<xliff:g id="APP_0">%1$s</xliff:g> ilovasiga <xliff:g id="APP_2">%2$s</xliff:g> ilovasidan fragmentlar ko‘rsatishga ruxsat berilsinmi?"</string>
<string name="slice_permission_text_1" msgid="6675965177075443714">"– <xliff:g id="APP">%1$s</xliff:g> ma’lumotlarini o‘qiy oladi"</string>
@@ -785,12 +794,18 @@
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Lupa oynasi sozlamalari"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Maxsus imkoniyatlarni ochish uchun bosing Sozlamalardan moslay yoki almashtira olasiz.\n\n"<annotation id="link">"Sozlamalar"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Vaqtinchalik berkitish uchun tugmani qirra tomon suring"</string>
+ <!-- no translation found for accessibility_floating_button_undo (511112888715708241) -->
+ <skip />
+ <!-- no translation found for accessibility_floating_button_undo_message_text (3044079592757099698) -->
+ <skip />
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Yuqori chapga surish"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Yuqori oʻngga surish"</string>
<string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Quyi chapga surish"</string>
<string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Quyi oʻngga surish"</string>
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Chetiga olib borish va yashirish"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Chetidan qaytarish va koʻrsatish"</string>
+ <!-- no translation found for accessibility_floating_button_action_remove_menu (6730432848162552135) -->
+ <skip />
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"oʻzgartirish"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Qurilmalarni boshqarish"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Boshqaruv elementlarini kiritish uchun ilovani tanlang"</string>
@@ -933,6 +948,10 @@
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobil internet"</string>
<string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Ulandi"</string>
+ <!-- no translation found for mobile_data_temp_connection_active (4590222725908806824) -->
+ <skip />
+ <!-- no translation found for mobile_data_poor_connection (819617772268371434) -->
+ <skip />
<string name="mobile_data_off_summary" msgid="3663995422004150567">"Mobil internetga avtomatik ulanmaydi"</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"Internetga ulanmagansiz"</string>
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"Boshqa tarmoqlar mavjud emas"</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 21200ca..8ea3408 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -248,7 +248,8 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Độ sáng"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Đảo màu"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Chỉnh màu"</string>
- <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Cài đặt người dùng"</string>
+ <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) -->
+ <skip />
<string name="quick_settings_done" msgid="2163641301648855793">"Xong"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Đóng"</string>
<string name="quick_settings_connected" msgid="3873605509184830379">"Đã kết nối"</string>
@@ -727,6 +728,14 @@
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Tắt dữ liệu di động?"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"Bạn sẽ không có quyền sử dụng dữ liệu hoặc truy cập Internet thông qua chế độ <xliff:g id="CARRIER">%s</xliff:g>. Bạn chỉ có thể truy cập Internet thông qua Wi-Fi."</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"nhà mạng của bạn"</string>
+ <!-- no translation found for auto_data_switch_disable_title (5146527155665190652) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_disable_message (5885533647399535852) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_negative_button (2370876875999891444) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_positive_button (8531782041263087564) -->
+ <skip />
<string name="touch_filtered_warning" msgid="8119511393338714836">"Vì ứng dụng đang che khuất yêu cầu cấp quyền nên Cài đặt không thể xác minh câu trả lời của bạn."</string>
<string name="slice_permission_title" msgid="3262615140094151017">"Cho phép <xliff:g id="APP_0">%1$s</xliff:g> hiển thị các lát của <xliff:g id="APP_2">%2$s</xliff:g>?"</string>
<string name="slice_permission_text_1" msgid="6675965177075443714">"- Có thể đọc thông tin từ <xliff:g id="APP">%1$s</xliff:g>"</string>
@@ -785,12 +794,18 @@
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Chế độ cài đặt cửa sổ phóng to"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Nhấn để mở bộ tính năng hỗ trợ tiếp cận. Tuỳ chỉnh/thay thế nút này trong phần Cài đặt.\n\n"<annotation id="link">"Xem chế độ cài đặt"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Di chuyển nút sang cạnh để ẩn nút tạm thời"</string>
+ <!-- no translation found for accessibility_floating_button_undo (511112888715708241) -->
+ <skip />
+ <!-- no translation found for accessibility_floating_button_undo_message_text (3044079592757099698) -->
+ <skip />
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Chuyển lên trên cùng bên trái"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Chuyển lên trên cùng bên phải"</string>
<string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Chuyển tới dưới cùng bên trái"</string>
<string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Chuyển tới dưới cùng bên phải"</string>
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Chuyển đến cạnh và ẩn"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Chuyển ra xa cạnh và hiển thị"</string>
+ <!-- no translation found for accessibility_floating_button_action_remove_menu (6730432848162552135) -->
+ <skip />
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"bật/tắt"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Điều khiển thiết bị"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Chọn ứng dụng để thêm các tùy chọn điều khiển"</string>
@@ -933,6 +948,10 @@
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Dữ liệu di động"</string>
<string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Đã kết nối"</string>
+ <!-- no translation found for mobile_data_temp_connection_active (4590222725908806824) -->
+ <skip />
+ <!-- no translation found for mobile_data_poor_connection (819617772268371434) -->
+ <skip />
<string name="mobile_data_off_summary" msgid="3663995422004150567">"Dữ liệu di động sẽ không tự động kết nối"</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"Không có kết nối mạng"</string>
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"Không có mạng nào khác"</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 83508a1..1cead42 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -248,7 +248,8 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"亮度"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"颜色反转"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"色彩校正"</string>
- <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"用户设置"</string>
+ <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) -->
+ <skip />
<string name="quick_settings_done" msgid="2163641301648855793">"完成"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"关闭"</string>
<string name="quick_settings_connected" msgid="3873605509184830379">"已连接"</string>
@@ -727,6 +728,14 @@
<string name="mobile_data_disable_title" msgid="5366476131671617790">"要关闭移动数据网络吗?"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"您将无法通过<xliff:g id="CARRIER">%s</xliff:g>使用移动数据或互联网,只能通过 WLAN 连接到互联网。"</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"您的运营商"</string>
+ <!-- no translation found for auto_data_switch_disable_title (5146527155665190652) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_disable_message (5885533647399535852) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_negative_button (2370876875999891444) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_positive_button (8531782041263087564) -->
+ <skip />
<string name="touch_filtered_warning" msgid="8119511393338714836">"由于某个应用遮挡了权限请求界面,因此“设置”应用无法验证您的回应。"</string>
<string name="slice_permission_title" msgid="3262615140094151017">"要允许“<xliff:g id="APP_0">%1$s</xliff:g>”显示“<xliff:g id="APP_2">%2$s</xliff:g>”图块吗?"</string>
<string name="slice_permission_text_1" msgid="6675965177075443714">"- 可以读取“<xliff:g id="APP">%1$s</xliff:g>”中的信息"</string>
@@ -785,12 +794,18 @@
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"放大镜窗口设置"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"点按即可打开无障碍功能。您可在“设置”中自定义或更换此按钮。\n\n"<annotation id="link">"查看设置"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"将按钮移到边缘,即可暂时将其隐藏"</string>
+ <!-- no translation found for accessibility_floating_button_undo (511112888715708241) -->
+ <skip />
+ <!-- no translation found for accessibility_floating_button_undo_message_text (3044079592757099698) -->
+ <skip />
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"移至左上角"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"移至右上角"</string>
<string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"移至左下角"</string>
<string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"移至右下角"</string>
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"移至边缘并隐藏"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"移至边缘以外并显示"</string>
+ <!-- no translation found for accessibility_floating_button_action_remove_menu (6730432848162552135) -->
+ <skip />
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"开启/关闭"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"设备控制器"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"选择要添加控制器的应用"</string>
@@ -933,6 +948,10 @@
<string name="mobile_data_settings_title" msgid="3955246641380064901">"移动数据网络"</string>
<string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"已连接"</string>
+ <!-- no translation found for mobile_data_temp_connection_active (4590222725908806824) -->
+ <skip />
+ <!-- no translation found for mobile_data_poor_connection (819617772268371434) -->
+ <skip />
<string name="mobile_data_off_summary" msgid="3663995422004150567">"系统将不会自动连接到移动数据网络"</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"无网络连接"</string>
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"没有其他可用网络"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 28420b3..cb90614 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -248,7 +248,8 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"亮度"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"色彩反轉"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"色彩校正"</string>
- <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"使用者設定"</string>
+ <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) -->
+ <skip />
<string name="quick_settings_done" msgid="2163641301648855793">"完成"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"關閉"</string>
<string name="quick_settings_connected" msgid="3873605509184830379">"已連線"</string>
@@ -727,6 +728,14 @@
<string name="mobile_data_disable_title" msgid="5366476131671617790">"要關閉流動數據嗎?"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"您無法透過「<xliff:g id="CARRIER">%s</xliff:g>」使用流動數據或互聯網。如要使用互聯網,您必須連接 Wi-Fi。"</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"您的流動網絡供應商"</string>
+ <!-- no translation found for auto_data_switch_disable_title (5146527155665190652) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_disable_message (5885533647399535852) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_negative_button (2370876875999891444) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_positive_button (8531782041263087564) -->
+ <skip />
<string name="touch_filtered_warning" msgid="8119511393338714836">"由於某個應用程式已阻擋權限要求畫面,因此「設定」應用程式無法驗證您的回應。"</string>
<string name="slice_permission_title" msgid="3262615140094151017">"要允許「<xliff:g id="APP_0">%1$s</xliff:g>」顯示「<xliff:g id="APP_2">%2$s</xliff:g>」的快訊嗎?"</string>
<string name="slice_permission_text_1" msgid="6675965177075443714">"- 可以讀取「<xliff:g id="APP">%1$s</xliff:g>」中的資料"</string>
@@ -785,12 +794,18 @@
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"放大鏡視窗設定"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"㩒一下就可以開無障礙功能。喺「設定」度自訂或者取代呢個按鈕。\n\n"<annotation id="link">"查看設定"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"將按鈕移到邊緣即可暫時隱藏"</string>
+ <!-- no translation found for accessibility_floating_button_undo (511112888715708241) -->
+ <skip />
+ <!-- no translation found for accessibility_floating_button_undo_message_text (3044079592757099698) -->
+ <skip />
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"移去左上方"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"移去右上方"</string>
<string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"移到左下方"</string>
<string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"移去右下方"</string>
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"移到邊緣並隱藏"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"從邊緣移出並顯示"</string>
+ <!-- no translation found for accessibility_floating_button_action_remove_menu (6730432848162552135) -->
+ <skip />
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"切換"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"裝置控制"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"選擇要新增控制項的應用程式"</string>
@@ -933,6 +948,10 @@
<string name="mobile_data_settings_title" msgid="3955246641380064901">"流動數據"</string>
<string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"已連線"</string>
+ <!-- no translation found for mobile_data_temp_connection_active (4590222725908806824) -->
+ <skip />
+ <!-- no translation found for mobile_data_poor_connection (819617772268371434) -->
+ <skip />
<string name="mobile_data_off_summary" msgid="3663995422004150567">"不會自動連線至流動數據"</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"沒有連線"</string>
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"沒有可用的其他網絡"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 8a1a9e2..ccad340 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -248,7 +248,8 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"亮度"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"色彩反轉"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"色彩校正"</string>
- <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"使用者設定"</string>
+ <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) -->
+ <skip />
<string name="quick_settings_done" msgid="2163641301648855793">"完成"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"關閉"</string>
<string name="quick_settings_connected" msgid="3873605509184830379">"已連線"</string>
@@ -727,6 +728,14 @@
<string name="mobile_data_disable_title" msgid="5366476131671617790">"要關閉行動數據嗎?"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"你將無法透過「<xliff:g id="CARRIER">%s</xliff:g>」使用行動數據或網際網路。你只能透過 Wi-Fi 使用網際網路。"</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"你的電信業者"</string>
+ <!-- no translation found for auto_data_switch_disable_title (5146527155665190652) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_disable_message (5885533647399535852) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_negative_button (2370876875999891444) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_positive_button (8531782041263087564) -->
+ <skip />
<string name="touch_filtered_warning" msgid="8119511393338714836">"由於某個應用程式覆蓋了權限要求畫面,因此「設定」應用程式無法驗證你的回應。"</string>
<string name="slice_permission_title" msgid="3262615140094151017">"要允許「<xliff:g id="APP_0">%1$s</xliff:g>」顯示「<xliff:g id="APP_2">%2$s</xliff:g>」的區塊嗎?"</string>
<string name="slice_permission_text_1" msgid="6675965177075443714">"- 它可以讀取「<xliff:g id="APP">%1$s</xliff:g>」的資訊"</string>
@@ -785,12 +794,18 @@
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"放大鏡視窗設定"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"輕觸即可開啟無障礙功能。你可以前往「設定」自訂或更換這個按鈕。\n\n"<annotation id="link">"查看設定"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"將按鈕移到邊緣處即可暫時隱藏"</string>
+ <!-- no translation found for accessibility_floating_button_undo (511112888715708241) -->
+ <skip />
+ <!-- no translation found for accessibility_floating_button_undo_message_text (3044079592757099698) -->
+ <skip />
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"移到左上方"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"移到右上方"</string>
<string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"移到左下方"</string>
<string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"移到右下方"</string>
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"移到邊緣並隱藏"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"從邊緣移出並顯示"</string>
+ <!-- no translation found for accessibility_floating_button_action_remove_menu (6730432848162552135) -->
+ <skip />
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"切換"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"裝置控制"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"選擇應用程式以新增控制項"</string>
@@ -933,6 +948,10 @@
<string name="mobile_data_settings_title" msgid="3955246641380064901">"行動數據"</string>
<string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"已連線"</string>
+ <!-- no translation found for mobile_data_temp_connection_active (4590222725908806824) -->
+ <skip />
+ <!-- no translation found for mobile_data_poor_connection (819617772268371434) -->
+ <skip />
<string name="mobile_data_off_summary" msgid="3663995422004150567">"系統將不會自動使用行動數據連線"</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"沒有網路連線"</string>
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"沒有可用的其他網路"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 9b376f0..b346494 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -248,7 +248,8 @@
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Ukugqama"</string>
<string name="quick_settings_inversion_label" msgid="3501527749494755688">"Ukuguqulwa kombala"</string>
<string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Ukulungiswa kombala"</string>
- <string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Amasethingi womsebenzisi"</string>
+ <!-- no translation found for quick_settings_more_user_settings (7634653308485206306) -->
+ <skip />
<string name="quick_settings_done" msgid="2163641301648855793">"Kwenziwe"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Vala"</string>
<string name="quick_settings_connected" msgid="3873605509184830379">"Ixhunyiwe"</string>
@@ -727,6 +728,14 @@
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Vala idatha yeselula?"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"Ngeke ube nokufinyelela kudatha noma ku-inthanethi nge-<xliff:g id="CARRIER">%s</xliff:g>. I-inthanethi izotholakala kuphela nge-Wi-Fi."</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"inkampani yakho yenethiwekhi"</string>
+ <!-- no translation found for auto_data_switch_disable_title (5146527155665190652) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_disable_message (5885533647399535852) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_negative_button (2370876875999891444) -->
+ <skip />
+ <!-- no translation found for auto_data_switch_dialog_positive_button (8531782041263087564) -->
+ <skip />
<string name="touch_filtered_warning" msgid="8119511393338714836">"Ngoba uhlelo lokusebenza lusitha isicelo semvume, Izilungiselelo azikwazi ukuqinisekisa impendulo yakho."</string>
<string name="slice_permission_title" msgid="3262615140094151017">"Vumela i-<xliff:g id="APP_0">%1$s</xliff:g> ukuthi ibonise izingcezu ze-<xliff:g id="APP_2">%2$s</xliff:g>?"</string>
<string name="slice_permission_text_1" msgid="6675965177075443714">"- Ingafunda ulwazi kusukela ku-<xliff:g id="APP">%1$s</xliff:g>"</string>
@@ -785,12 +794,18 @@
<string name="accessibility_magnification_magnifier_window_settings" msgid="2834685072221468434">"Amasethingi ewindi lesikhulisi"</string>
<string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Thepha ukuze uvule izakhi zokufinyelela. Enza ngendlela oyifisayo noma shintsha le nkinobho Kumasethingi.\n\n"<annotation id="link">"Buka amasethingi"</annotation></string>
<string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Hambisa inkinobho onqenqemeni ukuze uyifihle okwesikhashana"</string>
+ <!-- no translation found for accessibility_floating_button_undo (511112888715708241) -->
+ <skip />
+ <!-- no translation found for accessibility_floating_button_undo_message_text (3044079592757099698) -->
+ <skip />
<string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Hamba phezulu kwesokunxele"</string>
<string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Hamba phezulu ngakwesokudla"</string>
<string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Hamba phansi ngakwesokunxele"</string>
<string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Hamba phansi ngakwesokudla"</string>
<string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Hamba onqenqemeni ufihle"</string>
<string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Phuma onqenqemeni ubonise"</string>
+ <!-- no translation found for accessibility_floating_button_action_remove_menu (6730432848162552135) -->
+ <skip />
<string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"guqula"</string>
<string name="quick_controls_title" msgid="6839108006171302273">"Izilawuli zezinsiza"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Khetha uhlelo lokusebenza ukwengeza izilawuli"</string>
@@ -933,6 +948,10 @@
<string name="mobile_data_settings_title" msgid="3955246641380064901">"Idatha yeselula"</string>
<string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
<string name="mobile_data_connection_active" msgid="944490013299018227">"Ixhunyiwe"</string>
+ <!-- no translation found for mobile_data_temp_connection_active (4590222725908806824) -->
+ <skip />
+ <!-- no translation found for mobile_data_poor_connection (819617772268371434) -->
+ <skip />
<string name="mobile_data_off_summary" msgid="3663995422004150567">"Idatha yeselula ngeke ikwazi ukuxhuma ngokuzenzekelayo"</string>
<string name="mobile_data_no_connection" msgid="1713872434869947377">"Alukho uxhumano"</string>
<string name="non_carrier_network_unavailable" msgid="770049357024492372">"Awekho amanye amanethiwekhi atholakalayo"</string>
diff --git a/packages/SystemUI/res/values/integers.xml b/packages/SystemUI/res/values/integers.xml
index e30d441..8d44315 100644
--- a/packages/SystemUI/res/values/integers.xml
+++ b/packages/SystemUI/res/values/integers.xml
@@ -35,4 +35,6 @@
<!-- Percentage of displacement for items in QQS to guarantee matching with bottom of clock at
fade_out_complete_frame -->
<dimen name="percent_displacement_at_fade_out" format="float">0.1066</dimen>
+
+ <integer name="qs_carrier_max_em">7</integer>
</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/res/xml/media_session_collapsed.xml b/packages/SystemUI/res/xml/media_session_collapsed.xml
index 9115d42..148e5ec 100644
--- a/packages/SystemUI/res/xml/media_session_collapsed.xml
+++ b/packages/SystemUI/res/xml/media_session_collapsed.xml
@@ -34,6 +34,16 @@
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent" />
+ <!-- Touch ripple must have the same constraint as the album art. -->
+ <Constraint
+ android:id="@+id/touch_ripple_view"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/qs_media_session_height_collapsed"
+ app:layout_constraintStart_toStartOf="@+id/album_art"
+ app:layout_constraintEnd_toEndOf="@+id/album_art"
+ app:layout_constraintTop_toTopOf="@+id/album_art"
+ app:layout_constraintBottom_toBottomOf="@+id/album_art" />
+
<Constraint
android:id="@+id/header_title"
android:layout_width="wrap_content"
diff --git a/packages/SystemUI/res/xml/media_session_expanded.xml b/packages/SystemUI/res/xml/media_session_expanded.xml
index 522dc68..ac484d7 100644
--- a/packages/SystemUI/res/xml/media_session_expanded.xml
+++ b/packages/SystemUI/res/xml/media_session_expanded.xml
@@ -27,6 +27,16 @@
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent" />
+ <!-- Touch ripple must have the same constraint as the album art. -->
+ <Constraint
+ android:id="@+id/touch_ripple_view"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/qs_media_session_height_expanded"
+ app:layout_constraintStart_toStartOf="@+id/album_art"
+ app:layout_constraintEnd_toEndOf="@+id/album_art"
+ app:layout_constraintTop_toTopOf="@+id/album_art"
+ app:layout_constraintBottom_toBottomOf="@+id/album_art" />
+
<Constraint
android:id="@+id/header_title"
android:layout_width="wrap_content"
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/clocks/DefaultClockController.kt b/packages/SystemUI/shared/src/com/android/systemui/shared/clocks/DefaultClockController.kt
index da1d233..3961438 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/clocks/DefaultClockController.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/clocks/DefaultClockController.kt
@@ -237,6 +237,9 @@
) {
var isActive: Boolean = fraction < 0.5f
fun update(newFraction: Float): Pair<Boolean, Boolean> {
+ if (newFraction == fraction) {
+ return Pair(isActive, false)
+ }
val wasActive = isActive
val hasJumped =
(fraction == 0f && newFraction == 1f) || (fraction == 1f && newFraction == 0f)
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl
index 4613e8b..e743ec8 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl
@@ -110,4 +110,9 @@
* Sent when screen started turning off.
*/
void onScreenTurningOff() = 24;
+
+ /**
+ * Sent when split keyboard shortcut is triggered to enter stage split.
+ */
+ void enterStageSplitFromRunningApp(boolean leftOrTop) = 25;
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/regionsampling/RegionSamplingInstance.kt b/packages/SystemUI/shared/src/com/android/systemui/shared/regionsampling/RegionSampler.kt
similarity index 74%
rename from packages/SystemUI/shared/src/com/android/systemui/shared/regionsampling/RegionSamplingInstance.kt
rename to packages/SystemUI/shared/src/com/android/systemui/shared/regionsampling/RegionSampler.kt
index cd4b999..0ee813b 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/regionsampling/RegionSamplingInstance.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/regionsampling/RegionSampler.kt
@@ -24,15 +24,13 @@
import java.io.PrintWriter
import java.util.concurrent.Executor
-/**
- * Class for instance of RegionSamplingHelper
- */
-open class RegionSamplingInstance(
- sampledView: View?,
- mainExecutor: Executor?,
- bgExecutor: Executor?,
- regionSamplingEnabled: Boolean,
- updateFun: UpdateColorCallback
+/** Class for instance of RegionSamplingHelper */
+open class RegionSampler(
+ sampledView: View?,
+ mainExecutor: Executor?,
+ bgExecutor: Executor?,
+ regionSamplingEnabled: Boolean,
+ updateFun: UpdateColorCallback
) {
private var regionDarkness = RegionDarkness.DEFAULT
private var samplingBounds = Rect()
@@ -40,23 +38,13 @@
@VisibleForTesting var regionSampler: RegionSamplingHelper? = null
private var lightForegroundColor = Color.WHITE
private var darkForegroundColor = Color.BLACK
- /**
- * Interface for method to be passed into RegionSamplingHelper
- */
- @FunctionalInterface
- interface UpdateColorCallback {
- /**
- * Method to update the foreground colors after clock darkness changed.
- */
- fun updateColors()
- }
@VisibleForTesting
open fun createRegionSamplingHelper(
- sampledView: View,
- callback: SamplingCallback,
- mainExecutor: Executor?,
- bgExecutor: Executor?
+ sampledView: View,
+ callback: SamplingCallback,
+ mainExecutor: Executor?,
+ bgExecutor: Executor?
): RegionSamplingHelper {
return RegionSamplingHelper(sampledView, callback, mainExecutor, bgExecutor)
}
@@ -77,7 +65,7 @@
*
* @return the determined foreground color
*/
- fun currentForegroundColor(): Int{
+ fun currentForegroundColor(): Int {
return if (regionDarkness.isDark) {
lightForegroundColor
} else {
@@ -97,41 +85,37 @@
return regionDarkness
}
- /**
- * Start region sampler
- */
+ /** Start region sampler */
fun startRegionSampler() {
regionSampler?.start(samplingBounds)
}
- /**
- * Stop region sampler
- */
+ /** Stop region sampler */
fun stopRegionSampler() {
regionSampler?.stop()
}
- /**
- * Dump region sampler
- */
+ /** Dump region sampler */
fun dump(pw: PrintWriter) {
regionSampler?.dump(pw)
}
init {
if (regionSamplingEnabled && sampledView != null) {
- regionSampler = createRegionSamplingHelper(sampledView,
+ regionSampler =
+ createRegionSamplingHelper(
+ sampledView,
object : SamplingCallback {
override fun onRegionDarknessChanged(isRegionDark: Boolean) {
regionDarkness = convertToClockDarkness(isRegionDark)
- updateFun.updateColors()
+ updateFun()
}
/**
- * The method getLocationOnScreen is used to obtain the view coordinates
- * relative to its left and top edges on the device screen.
- * Directly accessing the X and Y coordinates of the view returns the
- * location relative to its parent view instead.
- */
+ * The method getLocationOnScreen is used to obtain the view coordinates
+ * relative to its left and top edges on the device screen. Directly
+ * accessing the X and Y coordinates of the view returns the location
+ * relative to its parent view instead.
+ */
override fun getSampledRegion(sampledView: View): Rect {
val screenLocation = tmpScreenLocation
sampledView.getLocationOnScreen(screenLocation)
@@ -147,8 +131,13 @@
override fun isSamplingEnabled(): Boolean {
return regionSamplingEnabled
}
- }, mainExecutor, bgExecutor)
+ },
+ mainExecutor,
+ bgExecutor
+ )
}
regionSampler?.setWindowVisible(true)
}
}
+
+typealias UpdateColorCallback = () -> Unit
diff --git a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
index 40a96b0..d48d7ff 100644
--- a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
+++ b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
@@ -34,25 +34,27 @@
import com.android.systemui.flags.Flags.REGION_SAMPLING
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
+import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.lifecycle.repeatWhenAttached
import com.android.systemui.log.dagger.KeyguardClockLog
import com.android.systemui.plugins.ClockController
import com.android.systemui.plugins.log.LogBuffer
-import com.android.systemui.shared.regionsampling.RegionSamplingInstance
+import com.android.systemui.shared.regionsampling.RegionSampler
import com.android.systemui.statusbar.policy.BatteryController
import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback
import com.android.systemui.statusbar.policy.ConfigurationController
-import java.io.PrintWriter
-import java.util.Locale
-import java.util.TimeZone
-import java.util.concurrent.Executor
-import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.DisposableHandle
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.launch
+import java.io.PrintWriter
+import java.util.Locale
+import java.util.TimeZone
+import java.util.concurrent.Executor
+import javax.inject.Inject
/**
* Controller for a Clock provided by the registry and used on the keyguard. Instantiated by
@@ -69,14 +71,17 @@
private val context: Context,
@Main private val mainExecutor: Executor,
@Background private val bgExecutor: Executor,
- @KeyguardClockLog private val logBuffer: LogBuffer,
+ @KeyguardClockLog private val logBuffer: LogBuffer?,
private val featureFlags: FeatureFlags
) {
var clock: ClockController? = null
set(value) {
field = value
if (value != null) {
- value.setLogBuffer(logBuffer)
+ if (logBuffer != null) {
+ value.setLogBuffer(logBuffer)
+ }
+
value.initialize(resources, dozeAmount, 0f)
updateRegionSamplers(value)
}
@@ -139,21 +144,17 @@
bgExecutor: Executor?,
regionSamplingEnabled: Boolean,
updateColors: () -> Unit
- ): RegionSamplingInstance {
- return RegionSamplingInstance(
+ ): RegionSampler {
+ return RegionSampler(
sampledView,
mainExecutor,
bgExecutor,
regionSamplingEnabled,
- object : RegionSamplingInstance.UpdateColorCallback {
- override fun updateColors() {
- updateColors()
- }
- })
+ updateFun = { updateColors() } )
}
- var smallRegionSampler: RegionSamplingInstance? = null
- var largeRegionSampler: RegionSamplingInstance? = null
+ var smallRegionSampler: RegionSampler? = null
+ var largeRegionSampler: RegionSampler? = null
private var smallClockIsDark = true
private var largeClockIsDark = true
@@ -161,6 +162,7 @@
private val configListener = object : ConfigurationController.ConfigurationListener {
override fun onThemeChanged() {
clock?.events?.onColorPaletteChanged(resources)
+ updateColors()
}
override fun onDensityOrFontScaleChanged() {
@@ -186,8 +188,10 @@
private val keyguardUpdateMonitorCallback = object : KeyguardUpdateMonitorCallback() {
override fun onKeyguardVisibilityChanged(visible: Boolean) {
isKeyguardVisible = visible
- if (!isKeyguardVisible) {
- clock?.animations?.doze(if (isDozing) 1f else 0f)
+ if (!featureFlags.isEnabled(DOZING_MIGRATION_1)) {
+ if (!isKeyguardVisible) {
+ clock?.animations?.doze(if (isDozing) 1f else 0f)
+ }
}
}
@@ -224,6 +228,7 @@
listenForDozing(this)
if (featureFlags.isEnabled(DOZING_MIGRATION_1)) {
listenForDozeAmountTransition(this)
+ listenForGoneToAodTransition(this)
} else {
listenForDozeAmount(this)
}
@@ -276,6 +281,22 @@
}
}
+ /**
+ * When keyguard is displayed again after being gone, the clock must be reset to full
+ * dozing.
+ */
+ @VisibleForTesting
+ internal fun listenForGoneToAodTransition(scope: CoroutineScope): Job {
+ return scope.launch {
+ keyguardTransitionInteractor.goneToAodTransition.filter {
+ it.transitionState == TransitionState.STARTED
+ }.collect {
+ dozeAmount = 1f
+ clock?.animations?.doze(dozeAmount)
+ }
+ }
+ }
+
@VisibleForTesting
internal fun listenForDozing(scope: CoroutineScope): Job {
return scope.launch {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
index 93ee151..c756a17 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -89,6 +89,7 @@
import com.android.systemui.Gefingerpoken;
import com.android.systemui.R;
import com.android.systemui.animation.Interpolators;
+import com.android.systemui.classifier.FalsingA11yDelegate;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.shared.system.SysUiStatsLog;
import com.android.systemui.statusbar.policy.BaseUserSwitcherAdapter;
@@ -136,6 +137,7 @@
private GlobalSettings mGlobalSettings;
private FalsingManager mFalsingManager;
private UserSwitcherController mUserSwitcherController;
+ private FalsingA11yDelegate mFalsingA11yDelegate;
private AlertDialog mAlertDialog;
private boolean mSwipeUpToRetry;
@@ -318,7 +320,8 @@
void initMode(@Mode int mode, GlobalSettings globalSettings, FalsingManager falsingManager,
UserSwitcherController userSwitcherController,
- UserSwitcherViewMode.UserSwitcherCallback userSwitcherCallback) {
+ UserSwitcherViewMode.UserSwitcherCallback userSwitcherCallback,
+ FalsingA11yDelegate falsingA11yDelegate) {
if (mCurrentMode == mode) return;
Log.i(TAG, "Switching mode from " + modeToString(mCurrentMode) + " to "
+ modeToString(mode));
@@ -337,6 +340,7 @@
}
mGlobalSettings = globalSettings;
mFalsingManager = falsingManager;
+ mFalsingA11yDelegate = falsingA11yDelegate;
mUserSwitcherController = userSwitcherController;
setupViewMode();
}
@@ -361,7 +365,7 @@
}
mViewMode.init(this, mGlobalSettings, mSecurityViewFlipper, mFalsingManager,
- mUserSwitcherController);
+ mUserSwitcherController, mFalsingA11yDelegate);
}
@Mode int getMode() {
@@ -723,7 +727,8 @@
default void init(@NonNull ConstraintLayout v, @NonNull GlobalSettings globalSettings,
@NonNull KeyguardSecurityViewFlipper viewFlipper,
@NonNull FalsingManager falsingManager,
- @NonNull UserSwitcherController userSwitcherController) {};
+ @NonNull UserSwitcherController userSwitcherController,
+ @NonNull FalsingA11yDelegate falsingA11yDelegate) {};
/** Reinitialize the location */
default void updateSecurityViewLocation() {};
@@ -828,7 +833,8 @@
public void init(@NonNull ConstraintLayout v, @NonNull GlobalSettings globalSettings,
@NonNull KeyguardSecurityViewFlipper viewFlipper,
@NonNull FalsingManager falsingManager,
- @NonNull UserSwitcherController userSwitcherController) {
+ @NonNull UserSwitcherController userSwitcherController,
+ @NonNull FalsingA11yDelegate falsingA11yDelegate) {
mView = v;
mViewFlipper = viewFlipper;
@@ -865,6 +871,7 @@
this::setupUserSwitcher;
private UserSwitcherCallback mUserSwitcherCallback;
+ private FalsingA11yDelegate mFalsingA11yDelegate;
UserSwitcherViewMode(UserSwitcherCallback userSwitcherCallback) {
mUserSwitcherCallback = userSwitcherCallback;
@@ -874,13 +881,15 @@
public void init(@NonNull ConstraintLayout v, @NonNull GlobalSettings globalSettings,
@NonNull KeyguardSecurityViewFlipper viewFlipper,
@NonNull FalsingManager falsingManager,
- @NonNull UserSwitcherController userSwitcherController) {
+ @NonNull UserSwitcherController userSwitcherController,
+ @NonNull FalsingA11yDelegate falsingA11yDelegate) {
init(v, viewFlipper, globalSettings, /* leftAlignedByDefault= */false);
mView = v;
mViewFlipper = viewFlipper;
mFalsingManager = falsingManager;
mUserSwitcherController = userSwitcherController;
mResources = v.getContext().getResources();
+ mFalsingA11yDelegate = falsingA11yDelegate;
if (mUserSwitcherViewGroup == null) {
LayoutInflater.from(v.getContext()).inflate(
@@ -978,6 +987,7 @@
mUserSwitcher.setText(currentUserName);
KeyguardUserSwitcherAnchor anchor = mView.findViewById(R.id.user_switcher_anchor);
+ anchor.setAccessibilityDelegate(mFalsingA11yDelegate);
BaseUserSwitcherAdapter adapter = new BaseUserSwitcherAdapter(mUserSwitcherController) {
@Override
@@ -1048,7 +1058,7 @@
anchor.setOnClickListener((v) -> {
if (mFalsingManager.isFalseTap(LOW_PENALTY)) return;
- mPopup = new KeyguardUserSwitcherPopupMenu(v.getContext(), mFalsingManager);
+ mPopup = new KeyguardUserSwitcherPopupMenu(mView.getContext(), mFalsingManager);
mPopup.setAnchorView(anchor);
mPopup.setAdapter(adapter);
mPopup.setOnItemClickListener((parent, view, pos, id) -> {
@@ -1137,7 +1147,8 @@
public void init(@NonNull ConstraintLayout v, @NonNull GlobalSettings globalSettings,
@NonNull KeyguardSecurityViewFlipper viewFlipper,
@NonNull FalsingManager falsingManager,
- @NonNull UserSwitcherController userSwitcherController) {
+ @NonNull UserSwitcherController userSwitcherController,
+ @NonNull FalsingA11yDelegate falsingA11yDelegate) {
init(v, viewFlipper, globalSettings, /* leftAlignedByDefault= */true);
mView = v;
mViewFlipper = viewFlipper;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
index 0b395a8..79a01b9 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
@@ -59,6 +59,7 @@
import com.android.systemui.Gefingerpoken;
import com.android.systemui.R;
import com.android.systemui.biometrics.SidefpsController;
+import com.android.systemui.classifier.FalsingA11yDelegate;
import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
@@ -100,6 +101,7 @@
private final FeatureFlags mFeatureFlags;
private final SessionTracker mSessionTracker;
private final Optional<SidefpsController> mSidefpsController;
+ private final FalsingA11yDelegate mFalsingA11yDelegate;
private int mLastOrientation = Configuration.ORIENTATION_UNDEFINED;
@@ -288,7 +290,8 @@
FeatureFlags featureFlags,
GlobalSettings globalSettings,
SessionTracker sessionTracker,
- Optional<SidefpsController> sidefpsController) {
+ Optional<SidefpsController> sidefpsController,
+ FalsingA11yDelegate falsingA11yDelegate) {
super(view);
mLockPatternUtils = lockPatternUtils;
mUpdateMonitor = keyguardUpdateMonitor;
@@ -309,6 +312,7 @@
mGlobalSettings = globalSettings;
mSessionTracker = sessionTracker;
mSidefpsController = sidefpsController;
+ mFalsingA11yDelegate = falsingA11yDelegate;
}
@Override
@@ -349,10 +353,21 @@
if (!mSidefpsController.isPresent()) {
return;
}
- if (mBouncerVisible
- && getResources().getBoolean(R.bool.config_show_sidefps_hint_on_bouncer)
- && mUpdateMonitor.isFingerprintDetectionRunning()
- && !mUpdateMonitor.userNeedsStrongAuth()) {
+ final boolean sfpsEnabled = getResources().getBoolean(
+ R.bool.config_show_sidefps_hint_on_bouncer);
+ final boolean fpsDetectionRunning = mUpdateMonitor.isFingerprintDetectionRunning();
+ final boolean needsStrongAuth = mUpdateMonitor.userNeedsStrongAuth();
+
+ boolean toShow = mBouncerVisible && sfpsEnabled && fpsDetectionRunning && !needsStrongAuth;
+
+ if (DEBUG) {
+ Log.d(TAG, "sideFpsToShow=" + toShow + ", "
+ + "mBouncerVisible=" + mBouncerVisible + ", "
+ + "configEnabled=" + sfpsEnabled + ", "
+ + "fpsDetectionRunning=" + fpsDetectionRunning + ", "
+ + "needsStrongAuth=" + needsStrongAuth);
+ }
+ if (toShow) {
mSidefpsController.get().show();
} else {
mSidefpsController.get().hide();
@@ -625,7 +640,7 @@
mView.initMode(mode, mGlobalSettings, mFalsingManager, mUserSwitcherController,
() -> showMessage(getContext().getString(R.string.keyguard_unlock_to_continue),
- null));
+ null), mFalsingA11yDelegate);
}
public void reportFailedUnlockAttempt(int userId, int timeoutMs) {
@@ -730,6 +745,7 @@
private final UserSwitcherController mUserSwitcherController;
private final SessionTracker mSessionTracker;
private final Optional<SidefpsController> mSidefpsController;
+ private final FalsingA11yDelegate mFalsingA11yDelegate;
@Inject
Factory(KeyguardSecurityContainer view,
@@ -749,7 +765,8 @@
FeatureFlags featureFlags,
GlobalSettings globalSettings,
SessionTracker sessionTracker,
- Optional<SidefpsController> sidefpsController) {
+ Optional<SidefpsController> sidefpsController,
+ FalsingA11yDelegate falsingA11yDelegate) {
mView = view;
mAdminSecondaryLockScreenControllerFactory = adminSecondaryLockScreenControllerFactory;
mLockPatternUtils = lockPatternUtils;
@@ -767,6 +784,7 @@
mUserSwitcherController = userSwitcherController;
mSessionTracker = sessionTracker;
mSidefpsController = sidefpsController;
+ mFalsingA11yDelegate = falsingA11yDelegate;
}
public KeyguardSecurityContainerController create(
@@ -777,7 +795,7 @@
mKeyguardStateController, securityCallback, mSecurityViewFlipperController,
mConfigurationController, mFalsingCollector, mFalsingManager,
mUserSwitcherController, mFeatureFlags, mGlobalSettings, mSessionTracker,
- mSidefpsController);
+ mSidefpsController, mFalsingA11yDelegate);
}
}
}
diff --git a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardLogger.kt b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardLogger.kt
index 46f3d4e..32ce537 100644
--- a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardLogger.kt
+++ b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardLogger.kt
@@ -21,6 +21,7 @@
import com.android.systemui.plugins.log.LogLevel
import com.android.systemui.plugins.log.LogLevel.DEBUG
import com.android.systemui.plugins.log.LogLevel.ERROR
+import com.android.systemui.plugins.log.LogLevel.INFO
import com.android.systemui.plugins.log.LogLevel.VERBOSE
import com.android.systemui.plugins.log.LogLevel.WARNING
import com.android.systemui.plugins.log.MessageInitializer
@@ -50,6 +51,14 @@
buffer.log(TAG, DEBUG, messageInitializer, messagePrinter)
}
+ fun v(msg: String, arg: Any) {
+ buffer.log(TAG, VERBOSE, { str1 = arg.toString() }, { "$msg: $str1" })
+ }
+
+ fun i(msg: String, arg: Any) {
+ buffer.log(TAG, INFO, { str1 = arg.toString() }, { "$msg: $str1" })
+ }
+
// TODO: remove after b/237743330 is fixed
fun logStatusBarCalculatedAlpha(alpha: Float) {
debugLog({ double1 = alpha.toDouble() }, { "Calculated new alpha: $double1" })
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
index d9f44cd..47ee71e 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
@@ -43,6 +43,7 @@
import com.android.systemui.dagger.GlobalRootComponent;
import com.android.systemui.dagger.SysUIComponent;
import com.android.systemui.dump.DumpManager;
+import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.util.NotificationChannels;
import java.util.Comparator;
@@ -137,7 +138,7 @@
if (mServicesStarted) {
final int N = mServices.length;
for (int i = 0; i < N; i++) {
- mServices[i].onBootCompleted();
+ notifyBootCompleted(mServices[i]);
}
}
}
@@ -256,7 +257,7 @@
for (i = 0; i < mServices.length; i++) {
if (mBootCompleteCache.isBootComplete()) {
- mServices[i].onBootCompleted();
+ notifyBootCompleted(mServices[i]);
}
mDumpManager.registerDumpable(mServices[i].getClass().getName(), mServices[i]);
@@ -267,7 +268,13 @@
mServicesStarted = true;
}
- private void timeInitialization(String clsName, Runnable init, TimingsTraceLog log,
+ private static void notifyBootCompleted(CoreStartable coreStartable) {
+ Trace.beginSection(coreStartable.getClass().getSimpleName() + ".onBootCompleted()");
+ coreStartable.onBootCompleted();
+ Trace.endSection();
+ }
+
+ private static void timeInitialization(String clsName, Runnable init, TimingsTraceLog log,
String metricsPrefix) {
long ti = System.currentTimeMillis();
log.traceBegin(metricsPrefix + " " + clsName);
@@ -281,11 +288,13 @@
}
}
- private CoreStartable startAdditionalStartable(String clsName) {
+ private static CoreStartable startAdditionalStartable(String clsName) {
CoreStartable startable;
if (DEBUG) Log.d(TAG, "loading: " + clsName);
try {
+ Trace.beginSection(clsName + ".newInstance()");
startable = (CoreStartable) Class.forName(clsName).newInstance();
+ Trace.endSection();
} catch (ClassNotFoundException
| IllegalAccessException
| InstantiationException ex) {
@@ -295,14 +304,19 @@
return startStartable(startable);
}
- private CoreStartable startStartable(String clsName, Provider<CoreStartable> provider) {
+ private static CoreStartable startStartable(String clsName, Provider<CoreStartable> provider) {
if (DEBUG) Log.d(TAG, "loading: " + clsName);
- return startStartable(provider.get());
+ Trace.beginSection("Provider<" + clsName + ">.get()");
+ CoreStartable startable = provider.get();
+ Trace.endSection();
+ return startStartable(startable);
}
- private CoreStartable startStartable(CoreStartable startable) {
+ private static CoreStartable startStartable(CoreStartable startable) {
if (DEBUG) Log.d(TAG, "running: " + startable);
+ Trace.beginSection(startable.getClass().getSimpleName() + ".start()");
startable.start();
+ Trace.endSection();
return startable;
}
@@ -340,11 +354,18 @@
@Override
public void onConfigurationChanged(Configuration newConfig) {
if (mServicesStarted) {
- mSysUIComponent.getConfigurationController().onConfigurationChanged(newConfig);
+ ConfigurationController configController = mSysUIComponent.getConfigurationController();
+ Trace.beginSection(
+ configController.getClass().getSimpleName() + ".onConfigurationChanged()");
+ configController.onConfigurationChanged(newConfig);
+ Trace.endSection();
int len = mServices.length;
for (int i = 0; i < len; i++) {
if (mServices[i] != null) {
+ Trace.beginSection(
+ mServices[i].getClass().getSimpleName() + ".onConfigurationChanged()");
mServices[i].onConfigurationChanged(newConfig);
+ Trace.endSection();
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewAppearance.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewAppearance.java
index 034e96a..4a9807f 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewAppearance.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewAppearance.java
@@ -136,11 +136,7 @@
final Rect draggableBounds = getWindowAvailableBounds();
// Initializes start position for mapping the translation of the menu view.
- final WindowMetrics windowMetrics = mWindowManager.getCurrentWindowMetrics();
- final WindowInsets windowInsets = windowMetrics.getWindowInsets();
- final Insets displayCutoutInsets = windowInsets.getInsetsIgnoringVisibility(
- WindowInsets.Type.displayCutout());
- draggableBounds.offset(-displayCutoutInsets.left, -displayCutoutInsets.top);
+ draggableBounds.offsetTo(/* newLeft= */ 0, /* newTop= */ 0);
draggableBounds.top += margin;
draggableBounds.right -= getMenuWidth();
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerController.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerController.java
index b1a64ed..c7be907 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerController.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerController.java
@@ -74,7 +74,8 @@
params.receiveInsetsIgnoringZOrder = true;
params.privateFlags |= PRIVATE_FLAG_EXCLUDE_FROM_SCREEN_MAGNIFICATION;
params.windowAnimations = android.R.style.Animation_Translucent;
- params.setFitInsetsTypes(WindowInsets.Type.navigationBars());
+ params.setFitInsetsTypes(
+ WindowInsets.Type.systemBars() | WindowInsets.Type.displayCutout());
return params;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/broadcast/UserBroadcastDispatcher.kt b/packages/SystemUI/src/com/android/systemui/broadcast/UserBroadcastDispatcher.kt
index 22dc94a..5850c95 100644
--- a/packages/SystemUI/src/com/android/systemui/broadcast/UserBroadcastDispatcher.kt
+++ b/packages/SystemUI/src/com/android/systemui/broadcast/UserBroadcastDispatcher.kt
@@ -21,6 +21,7 @@
import android.content.Context
import android.os.Handler
import android.os.Looper
+import android.os.Trace
import android.os.UserHandle
import android.util.ArrayMap
import android.util.ArraySet
@@ -126,6 +127,7 @@
action,
userId,
{
+ Trace.beginSection("registerReceiver act=$action user=$userId")
context.registerReceiverAsUser(
this,
UserHandle.of(userId),
@@ -134,11 +136,14 @@
workerHandler,
flags
)
+ Trace.endSection()
logger.logContextReceiverRegistered(userId, flags, it)
},
{
try {
+ Trace.beginSection("unregisterReceiver act=$action user=$userId")
context.unregisterReceiver(this)
+ Trace.endSection()
logger.logContextReceiverUnregistered(userId, action)
} catch (e: IllegalArgumentException) {
Log.e(TAG, "Trying to unregister unregistered receiver for user $userId, " +
diff --git a/packages/SystemUI/src/com/android/systemui/charging/WiredChargingRippleController.kt b/packages/SystemUI/src/com/android/systemui/charging/WiredChargingRippleController.kt
index dec3d6b..616e49c 100644
--- a/packages/SystemUI/src/com/android/systemui/charging/WiredChargingRippleController.kt
+++ b/packages/SystemUI/src/com/android/systemui/charging/WiredChargingRippleController.kt
@@ -149,7 +149,7 @@
}
fun startRipple() {
- if (rippleView.rippleInProgress || rippleView.parent != null) {
+ if (rippleView.rippleInProgress() || rippleView.parent != null) {
// Skip if ripple is still playing, or not playing but already added the parent
// (which might happen just before the animation starts or right after
// the animation ends.)
diff --git a/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingLayout.java b/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingLayout.java
index c0cc6b4..1455699 100644
--- a/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingLayout.java
@@ -33,9 +33,9 @@
import com.android.settingslib.Utils;
import com.android.systemui.R;
import com.android.systemui.animation.Interpolators;
+import com.android.systemui.ripple.RippleAnimationConfig;
import com.android.systemui.ripple.RippleShader.RippleShape;
import com.android.systemui.ripple.RippleView;
-import com.android.systemui.ripple.RippleViewKt;
import java.text.NumberFormat;
@@ -150,7 +150,7 @@
mRippleView.setColor(color, 28);
} else {
mRippleView.setDuration(CIRCLE_RIPPLE_ANIMATION_DURATION);
- mRippleView.setColor(color, RippleViewKt.RIPPLE_DEFAULT_ALPHA);
+ mRippleView.setColor(color, RippleAnimationConfig.RIPPLE_DEFAULT_ALPHA);
}
OnAttachStateChangeListener listener = new OnAttachStateChangeListener() {
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java b/packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java
index 500f280..2245d84 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java
@@ -337,7 +337,8 @@
|| mTestHarness
|| mDataProvider.isJustUnlockedWithFace()
|| mDataProvider.isDocked()
- || mAccessibilityManager.isTouchExplorationEnabled();
+ || mAccessibilityManager.isTouchExplorationEnabled()
+ || mDataProvider.isA11yAction();
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingA11yDelegate.kt b/packages/SystemUI/src/com/android/systemui/classifier/FalsingA11yDelegate.kt
new file mode 100644
index 0000000..63d57cc
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingA11yDelegate.kt
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.classifier
+
+import android.os.Bundle
+import android.view.View
+import android.view.accessibility.AccessibilityNodeInfo.ACTION_CLICK
+import javax.inject.Inject
+
+/**
+ * Class that injects an artificial tap into the falsing collector.
+ *
+ * This is used for views that can be interacted with by A11y services and have falsing checks, as
+ * the gestures made by the A11y framework do not propagate motion events down the view hierarchy.
+ */
+class FalsingA11yDelegate @Inject constructor(private val falsingCollector: FalsingCollector) :
+ View.AccessibilityDelegate() {
+ override fun performAccessibilityAction(host: View?, action: Int, args: Bundle?): Boolean {
+ if (action == ACTION_CLICK) {
+ falsingCollector.onA11yAction()
+ }
+ return super.performAccessibilityAction(host, action, args)
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollector.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollector.java
index 858bac3..6670108 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollector.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollector.java
@@ -132,5 +132,8 @@
/** */
void updateFalseConfidence(FalsingClassifier.Result result);
+
+ /** Indicates an a11y action was made. */
+ void onA11yAction();
}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorFake.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorFake.java
index 0b7d6ab..cc25368 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorFake.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorFake.java
@@ -157,4 +157,8 @@
@Override
public void updateFalseConfidence(FalsingClassifier.Result result) {
}
+
+ @Override
+ public void onA11yAction() {
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java
index da3d293..8bdef13 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java
@@ -375,6 +375,15 @@
mHistoryTracker.addResults(Collections.singleton(result), mSystemClock.uptimeMillis());
}
+ @Override
+ public void onA11yAction() {
+ if (mPendingDownEvent != null) {
+ mPendingDownEvent.recycle();
+ mPendingDownEvent = null;
+ }
+ mFalsingDataProvider.onA11yAction();
+ }
+
private boolean shouldSessionBeActive() {
return mScreenOn && (mState == StatusBarState.KEYGUARD) && !mShowingAod;
}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingDataProvider.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingDataProvider.java
index 3991a35..09ebeea 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingDataProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingDataProvider.java
@@ -59,6 +59,7 @@
private MotionEvent mFirstRecentMotionEvent;
private MotionEvent mLastMotionEvent;
private boolean mJustUnlockedWithFace;
+ private boolean mA11YAction;
@Inject
public FalsingDataProvider(
@@ -124,6 +125,7 @@
mPriorMotionEvents = mRecentMotionEvents;
mRecentMotionEvents = new TimeLimitedMotionEventBuffer(MOTION_EVENT_AGE_MS);
}
+ mA11YAction = false;
}
/** Returns screen width in pixels. */
@@ -334,6 +336,17 @@
mGestureFinalizedListeners.remove(listener);
}
+ /** Return whether last gesture was an A11y action. */
+ public boolean isA11yAction() {
+ return mA11YAction;
+ }
+
+ /** Set whether last gesture was an A11y action. */
+ public void onA11yAction() {
+ completePriorGesture();
+ this.mA11YAction = true;
+ }
+
void onSessionStarted() {
mSessionListeners.forEach(SessionListener::onSessionStarted);
}
diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java
index 9f338d1..c853671 100644
--- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java
+++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java
@@ -31,6 +31,7 @@
import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_SWIPE_DISMISSED;
import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_TAP_OUTSIDE;
import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_TIMED_OUT;
+import static com.android.systemui.flags.Flags.CLIPBOARD_REMOTE_BEHAVIOR;
import static java.util.Objects.requireNonNull;
@@ -73,6 +74,7 @@
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.broadcast.BroadcastSender;
import com.android.systemui.clipboardoverlay.dagger.ClipboardOverlayModule.OverlayWindowContext;
+import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.screenshot.TimeoutHandler;
import java.io.IOException;
@@ -101,6 +103,8 @@
private final ClipboardOverlayWindow mWindow;
private final TimeoutHandler mTimeoutHandler;
private final TextClassifier mTextClassifier;
+ private final ClipboardOverlayUtils mClipboardUtils;
+ private final FeatureFlags mFeatureFlags;
private final ClipboardOverlayView mView;
@@ -119,11 +123,15 @@
private Animator mExitAnimator;
private Animator mEnterAnimator;
+ private Runnable mOnUiUpdate;
+
private final ClipboardOverlayView.ClipboardOverlayCallbacks mClipboardCallbacks =
new ClipboardOverlayView.ClipboardOverlayCallbacks() {
@Override
public void onInteraction() {
- mTimeoutHandler.resetTimeout();
+ if (mOnUiUpdate != null) {
+ mOnUiUpdate.run();
+ }
}
@Override
@@ -178,7 +186,10 @@
ClipboardOverlayWindow clipboardOverlayWindow,
BroadcastDispatcher broadcastDispatcher,
BroadcastSender broadcastSender,
- TimeoutHandler timeoutHandler, UiEventLogger uiEventLogger) {
+ TimeoutHandler timeoutHandler,
+ FeatureFlags featureFlags,
+ ClipboardOverlayUtils clipboardUtils,
+ UiEventLogger uiEventLogger) {
mBroadcastDispatcher = broadcastDispatcher;
mDisplayManager = requireNonNull(context.getSystemService(DisplayManager.class));
final Context displayContext = context.createDisplayContext(getDefaultDisplay());
@@ -199,6 +210,9 @@
mTimeoutHandler = timeoutHandler;
mTimeoutHandler.setDefaultTimeoutMillis(CLIPBOARD_DEFAULT_TIMEOUT_MILLIS);
+ mFeatureFlags = featureFlags;
+ mClipboardUtils = clipboardUtils;
+
mView.setCallbacks(mClipboardCallbacks);
@@ -257,11 +271,13 @@
boolean isSensitive = clipData != null && clipData.getDescription().getExtras() != null
&& clipData.getDescription().getExtras()
.getBoolean(ClipDescription.EXTRA_IS_SENSITIVE);
+ boolean isRemote = mFeatureFlags.isEnabled(CLIPBOARD_REMOTE_BEHAVIOR)
+ && mClipboardUtils.isRemoteCopy(mContext, clipData, clipSource);
if (clipData == null || clipData.getItemCount() == 0) {
mView.showDefaultTextPreview();
} else if (!TextUtils.isEmpty(clipData.getItemAt(0).getText())) {
ClipData.Item item = clipData.getItemAt(0);
- if (DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SYSTEMUI,
+ if (isRemote || DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SYSTEMUI,
CLIPBOARD_OVERLAY_SHOW_ACTIONS, false)) {
if (item.getTextLinks() != null) {
AsyncTask.execute(() -> classifyText(clipData.getItemAt(0), clipSource));
@@ -287,7 +303,13 @@
maybeShowRemoteCopy(clipData);
animateIn();
mView.announceForAccessibility(accessibilityAnnouncement);
- mTimeoutHandler.resetTimeout();
+ if (isRemote) {
+ mTimeoutHandler.cancelTimeout();
+ mOnUiUpdate = null;
+ } else {
+ mOnUiUpdate = mTimeoutHandler::resetTimeout;
+ mOnUiUpdate.run();
+ }
}
private void maybeShowRemoteCopy(ClipData clipData) {
@@ -427,7 +449,9 @@
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
- mTimeoutHandler.resetTimeout();
+ if (mOnUiUpdate != null) {
+ mOnUiUpdate.run();
+ }
}
});
mEnterAnimator.start();
diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayUtils.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayUtils.java
new file mode 100644
index 0000000..cece764
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayUtils.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.clipboardoverlay;
+
+import android.content.ClipData;
+import android.content.ClipDescription;
+import android.content.ComponentName;
+import android.content.Context;
+
+import com.android.systemui.R;
+
+import javax.inject.Inject;
+
+class ClipboardOverlayUtils {
+
+ @Inject
+ ClipboardOverlayUtils() {
+ }
+
+ boolean isRemoteCopy(Context context, ClipData clipData, String clipSource) {
+ if (clipData != null && clipData.getDescription().getExtras() != null
+ && clipData.getDescription().getExtras().getBoolean(
+ ClipDescription.EXTRA_IS_REMOTE_DEVICE)) {
+ ComponentName remoteComponent = ComponentName.unflattenFromString(
+ context.getResources().getString(R.string.config_remoteCopyPackage));
+ if (remoteComponent != null) {
+ return remoteComponent.getPackageName().equals(clipSource);
+ }
+ }
+ return false;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
index bf7d716..6cb0e8b 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
@@ -24,7 +24,6 @@
import android.content.ComponentName
import android.content.Context
import android.content.Intent
-import android.content.SharedPreferences
import android.graphics.drawable.Drawable
import android.graphics.drawable.LayerDrawable
import android.service.controls.Control
@@ -59,7 +58,10 @@
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.globalactions.GlobalActionsPopupMenu
import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.settings.UserFileManager
+import com.android.systemui.settings.UserTracker
import com.android.systemui.shade.ShadeController
+import com.android.systemui.statusbar.policy.DeviceControlsControllerImpl
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.util.concurrency.DelayableExecutor
import dagger.Lazy
@@ -76,13 +78,14 @@
@Main val uiExecutor: DelayableExecutor,
@Background val bgExecutor: DelayableExecutor,
val controlsListingController: Lazy<ControlsListingController>,
- @Main val sharedPreferences: SharedPreferences,
val controlActionCoordinator: ControlActionCoordinator,
private val activityStarter: ActivityStarter,
private val shadeController: ShadeController,
private val iconCache: CustomIconCache,
private val controlsMetricsLogger: ControlsMetricsLogger,
- private val keyguardStateController: KeyguardStateController
+ private val keyguardStateController: KeyguardStateController,
+ private val userFileManager: UserFileManager,
+ private val userTracker: UserTracker,
) : ControlsUiController {
companion object {
@@ -110,6 +113,12 @@
private lateinit var onDismiss: Runnable
private val popupThemedContext = ContextThemeWrapper(context, R.style.Control_ListPopupWindow)
private var retainCache = false
+ private val sharedPreferences
+ get() = userFileManager.getSharedPreferences(
+ fileName = DeviceControlsControllerImpl.PREFS_CONTROLS_FILE,
+ mode = 0,
+ userId = userTracker.userId
+ )
private val collator = Collator.getInstance(context.resources.configuration.locales[0])
private val localeComparator = compareBy<SelectionItem, CharSequence>(collator) {
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java
index 48bef97..2bee75e 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java
@@ -41,6 +41,7 @@
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.RecentsImplementation;
import com.android.systemui.screenshot.ReferenceScreenshotModule;
+import com.android.systemui.settings.dagger.MultiUserUtilsModule;
import com.android.systemui.shade.NotificationShadeWindowControllerImpl;
import com.android.systemui.shade.ShadeController;
import com.android.systemui.shade.ShadeControllerImpl;
@@ -93,6 +94,7 @@
AospPolicyModule.class,
GestureModule.class,
MediaModule.class,
+ MultiUserUtilsModule.class,
PowerModule.class,
QSModule.class,
ReferenceScreenshotModule.class,
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index 6db56210..482bdaf 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -58,7 +58,6 @@
import com.android.systemui.recents.Recents;
import com.android.systemui.screenshot.dagger.ScreenshotModule;
import com.android.systemui.security.data.repository.SecurityRepositoryModule;
-import com.android.systemui.settings.dagger.MultiUserUtilsModule;
import com.android.systemui.shade.ShadeController;
import com.android.systemui.smartspace.dagger.SmartspaceModule;
import com.android.systemui.statusbar.CommandQueue;
@@ -140,7 +139,6 @@
PrivacyModule.class,
ScreenshotModule.class,
SensorModule.class,
- MultiUserUtilsModule.class,
SecurityRepositoryModule.class,
SettingsUtilModule.class,
SmartRepliesInflationModule.class,
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index a4d3399e..8bcf9f6 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -122,7 +122,8 @@
* Migration from the legacy isDozing/dozeAmount paths to the new KeyguardTransitionRepository
* will occur in stages. This is one stage of many to come.
*/
- @JvmField val DOZING_MIGRATION_1 = UnreleasedFlag(213, teamfood = true)
+ // TODO(b/255607168): Tracking Bug
+ @JvmField val DOZING_MIGRATION_1 = UnreleasedFlag(213)
@JvmField val NEW_ELLIPSE_DETECTION = UnreleasedFlag(214)
@@ -229,7 +230,7 @@
@JvmField val DREAM_MEDIA_TAP_TO_OPEN = UnreleasedFlag(906)
// TODO(b/254513168): Tracking Bug
- val UMO_SURFACE_RIPPLE = UnreleasedFlag(907)
+ @JvmField val UMO_SURFACE_RIPPLE = UnreleasedFlag(907)
// 1000 - dock
val SIMULATE_DOCK_THROUGH_CHARGING = ReleasedFlag(1000)
@@ -238,11 +239,13 @@
@JvmField val ROUNDED_BOX_RIPPLE = ReleasedFlag(1002)
// 1100 - windowing
+ @JvmField
@Keep
val WM_ENABLE_SHELL_TRANSITIONS =
SysPropBooleanFlag(1100, "persist.wm.debug.shell_transit", false)
/** b/170163464: animate bubbles expanded view collapse with home gesture */
+ @JvmField
@Keep
val BUBBLES_HOME_GESTURE =
SysPropBooleanFlag(1101, "persist.wm.debug.bubbles_home_gesture", true)
@@ -264,40 +267,50 @@
@Keep
val HIDE_NAVBAR_WINDOW = SysPropBooleanFlag(1103, "persist.wm.debug.hide_navbar_window", false)
+ @JvmField
@Keep
val WM_DESKTOP_WINDOWING = SysPropBooleanFlag(1104, "persist.wm.debug.desktop_mode", false)
+ @JvmField
@Keep
val WM_CAPTION_ON_SHELL = SysPropBooleanFlag(1105, "persist.wm.debug.caption_on_shell", false)
+ @JvmField
@Keep
val FLOATING_TASKS_ENABLED = SysPropBooleanFlag(1106, "persist.wm.debug.floating_tasks", false)
+ @JvmField
@Keep
val SHOW_FLOATING_TASKS_AS_BUBBLES =
SysPropBooleanFlag(1107, "persist.wm.debug.floating_tasks_as_bubbles", false)
+ @JvmField
@Keep
val ENABLE_FLING_TO_DISMISS_BUBBLE =
SysPropBooleanFlag(1108, "persist.wm.debug.fling_to_dismiss_bubble", true)
+ @JvmField
@Keep
val ENABLE_FLING_TO_DISMISS_PIP =
SysPropBooleanFlag(1109, "persist.wm.debug.fling_to_dismiss_pip", true)
+ @JvmField
@Keep
val ENABLE_PIP_KEEP_CLEAR_ALGORITHM =
SysPropBooleanFlag(1110, "persist.wm.debug.enable_pip_keep_clear_algorithm", false)
// 1200 - predictive back
+ @JvmField
@Keep
val WM_ENABLE_PREDICTIVE_BACK =
SysPropBooleanFlag(1200, "persist.wm.debug.predictive_back", true)
+ @JvmField
@Keep
val WM_ENABLE_PREDICTIVE_BACK_ANIM =
SysPropBooleanFlag(1201, "persist.wm.debug.predictive_back_anim", false)
+ @JvmField
@Keep
val WM_ALWAYS_ENFORCE_PREDICTIVE_BACK =
SysPropBooleanFlag(1202, "persist.wm.debug.predictive_back_always_enforce", false)
@@ -307,7 +320,7 @@
// 1300 - screenshots
// TODO(b/254512719): Tracking Bug
- @JvmField val SCREENSHOT_REQUEST_PROCESSOR = UnreleasedFlag(1300)
+ @JvmField val SCREENSHOT_REQUEST_PROCESSOR = UnreleasedFlag(1300, true)
// TODO(b/254513155): Tracking Bug
@JvmField val SCREENSHOT_WORK_PROFILE_POLICY = UnreleasedFlag(1301)
@@ -325,6 +338,7 @@
// 1700 - clipboard
@JvmField val CLIPBOARD_OVERLAY_REFACTOR = UnreleasedFlag(1700)
+ @JvmField val CLIPBOARD_REMOTE_BEHAVIOR = UnreleasedFlag(1701)
// 1800 - shade container
@JvmField val LEAVE_SHADE_OPEN_FOR_BUGREPORT = UnreleasedFlag(1800, teamfood = true)
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 b186ae0..6baaf5f 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
@@ -21,7 +21,10 @@
import com.android.systemui.common.shared.model.Position
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.doze.DozeHost
+import com.android.systemui.keyguard.WakefulnessLifecycle
+import com.android.systemui.keyguard.WakefulnessLifecycle.Wakefulness
import com.android.systemui.keyguard.shared.model.StatusBarState
+import com.android.systemui.keyguard.shared.model.WakefulnessModel
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.statusbar.policy.KeyguardStateController
import javax.inject.Inject
@@ -89,6 +92,9 @@
/** Observable for the [StatusBarState] */
val statusBarState: Flow<StatusBarState>
+ /** Observable for device wake/sleep state */
+ val wakefulnessState: Flow<WakefulnessModel>
+
/**
* Returns `true` if the keyguard is showing; `false` otherwise.
*
@@ -118,6 +124,7 @@
statusBarStateController: StatusBarStateController,
private val keyguardStateController: KeyguardStateController,
dozeHost: DozeHost,
+ wakefulnessLifecycle: WakefulnessLifecycle,
) : KeyguardRepository {
private val _animateBottomAreaDozingTransitions = MutableStateFlow(false)
override val animateBottomAreaDozingTransitions =
@@ -207,6 +214,40 @@
awaitClose { statusBarStateController.removeCallback(callback) }
}
+ override val wakefulnessState: Flow<WakefulnessModel> = conflatedCallbackFlow {
+ val callback =
+ object : WakefulnessLifecycle.Observer {
+ override fun onStartedWakingUp() {
+ trySendWithFailureLogging(
+ WakefulnessModel.STARTING_TO_WAKE,
+ TAG,
+ "Wakefulness: starting to wake"
+ )
+ }
+ override fun onFinishedWakingUp() {
+ trySendWithFailureLogging(WakefulnessModel.AWAKE, TAG, "Wakefulness: awake")
+ }
+ override fun onStartedGoingToSleep() {
+ trySendWithFailureLogging(
+ WakefulnessModel.STARTING_TO_SLEEP,
+ TAG,
+ "Wakefulness: starting to sleep"
+ )
+ }
+ override fun onFinishedGoingToSleep() {
+ trySendWithFailureLogging(WakefulnessModel.ASLEEP, TAG, "Wakefulness: asleep")
+ }
+ }
+ wakefulnessLifecycle.addObserver(callback)
+ trySendWithFailureLogging(
+ wakefulnessIntToObject(wakefulnessLifecycle.getWakefulness()),
+ TAG,
+ "initial wakefulness state"
+ )
+
+ awaitClose { wakefulnessLifecycle.removeObserver(callback) }
+ }
+
override fun setAnimateDozingTransitions(animate: Boolean) {
_animateBottomAreaDozingTransitions.value = animate
}
@@ -228,6 +269,16 @@
}
}
+ private fun wakefulnessIntToObject(@Wakefulness value: Int): WakefulnessModel {
+ return when (value) {
+ 0 -> WakefulnessModel.ASLEEP
+ 1 -> WakefulnessModel.STARTING_TO_WAKE
+ 2 -> WakefulnessModel.AWAKE
+ 3 -> WakefulnessModel.STARTING_TO_SLEEP
+ else -> throw IllegalArgumentException("Invalid Wakefulness value: $value")
+ }
+ }
+
companion object {
private const val TAG = "KeyguardRepositoryImpl"
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryModule.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryModule.kt
index d15d7f2..0c72520 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryModule.kt
@@ -22,4 +22,9 @@
@Module
interface KeyguardRepositoryModule {
@Binds fun keyguardRepository(impl: KeyguardRepositoryImpl): KeyguardRepository
+
+ @Binds
+ fun keyguardTransitionRepository(
+ impl: KeyguardTransitionRepositoryImpl
+ ): KeyguardTransitionRepository
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt
index ab25597..e3d1a27 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt
@@ -29,27 +29,33 @@
import com.android.systemui.keyguard.shared.model.TransitionStep
import java.util.UUID
import javax.inject.Inject
+import kotlinx.coroutines.channels.BufferOverflow
import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.MutableSharedFlow
+import kotlinx.coroutines.flow.asSharedFlow
+import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filter
-@SysUISingleton
-class KeyguardTransitionRepository @Inject constructor() {
- /*
- * Each transition between [KeyguardState]s will have an associated Flow.
- * In order to collect these events, clients should call [transition].
+/**
+ * The source of truth for all keyguard transitions.
+ *
+ * While the keyguard component is visible, it can undergo a number of transitions between different
+ * UI screens, such as AOD (Always-on Display), Bouncer, and others mentioned in [KeyguardState].
+ * These UI elements should listen to events emitted by [transitions], to ensure a centrally
+ * coordinated experience.
+ *
+ * To create or modify logic that controls when and how transitions get created, look at
+ * [TransitionInteractor]. These interactors will call [startTransition] and [updateTransition] on
+ * this repository.
+ */
+interface KeyguardTransitionRepository {
+ /**
+ * All events regarding transitions, as they start, run, and complete. [TransitionStep#value] is
+ * a float between [0, 1] representing progress towards completion. If this is a user driven
+ * transition, that value may not be a monotonic progression, as the user may swipe in any
+ * direction.
*/
- private val _transitions = MutableStateFlow(TransitionStep())
- val transitions = _transitions.asStateFlow()
-
- /* Information about the active transition. */
- private var currentTransitionInfo: TransitionInfo? = null
- /*
- * When manual control of the transition is requested, a unique [UUID] is used as the handle
- * to permit calls to [updateTransition]
- */
- private var updateTransitionId: UUID? = null
+ val transitions: Flow<TransitionStep>
/**
* Interactors that require information about changes between [KeyguardState]s will call this to
@@ -60,65 +66,10 @@
}
/**
- * Begin a transition from one state to another. The [info.from] must match
- * [currentTransitionInfo.to], or the request will be denied. This is enforced to avoid
- * unplanned transitions.
+ * Begin a transition from one state to another. Will not start if another transition is in
+ * progress.
*/
- fun startTransition(info: TransitionInfo): UUID? {
- if (currentTransitionInfo != null) {
- // Open questions:
- // * Queue of transitions? buffer of 1?
- // * Are transitions cancellable if a new one is triggered?
- // * What validation does this need to do?
- Log.wtf(TAG, "Transition still active: $currentTransitionInfo")
- return null
- }
- currentTransitionInfo?.animator?.cancel()
-
- currentTransitionInfo = info
- info.animator?.let { animator ->
- // An animator was provided, so use it to run the transition
- animator.setFloatValues(0f, 1f)
- val updateListener =
- object : AnimatorUpdateListener {
- override fun onAnimationUpdate(animation: ValueAnimator) {
- emitTransition(
- info,
- (animation.getAnimatedValue() as Float),
- TransitionState.RUNNING
- )
- }
- }
- val adapter =
- object : AnimatorListenerAdapter() {
- override fun onAnimationStart(animation: Animator) {
- Log.i(TAG, "Starting transition: $info")
- emitTransition(info, 0f, TransitionState.STARTED)
- }
- override fun onAnimationCancel(animation: Animator) {
- Log.i(TAG, "Cancelling transition: $info")
- }
- override fun onAnimationEnd(animation: Animator) {
- Log.i(TAG, "Ending transition: $info")
- emitTransition(info, 1f, TransitionState.FINISHED)
- animator.removeListener(this)
- animator.removeUpdateListener(updateListener)
- }
- }
- animator.addListener(adapter)
- animator.addUpdateListener(updateListener)
- animator.start()
- return@startTransition null
- }
- ?: run {
- Log.i(TAG, "Starting transition (manual): $info")
- emitTransition(info, 0f, TransitionState.STARTED)
-
- // No animator, so it's manual. Provide a mechanism to callback
- updateTransitionId = UUID.randomUUID()
- return@startTransition updateTransitionId
- }
- }
+ fun startTransition(info: TransitionInfo): UUID?
/**
* Allows manual control of a transition. When calling [startTransition], the consumer must pass
@@ -132,58 +83,127 @@
transitionId: UUID,
@FloatRange(from = 0.0, to = 1.0) value: Float,
state: TransitionState
+ )
+}
+
+@SysUISingleton
+class KeyguardTransitionRepositoryImpl @Inject constructor() : KeyguardTransitionRepository {
+ /*
+ * Each transition between [KeyguardState]s will have an associated Flow.
+ * In order to collect these events, clients should call [transition].
+ */
+ private val _transitions =
+ MutableSharedFlow<TransitionStep>(
+ extraBufferCapacity = 10,
+ onBufferOverflow = BufferOverflow.DROP_OLDEST
+ )
+ override val transitions = _transitions.asSharedFlow().distinctUntilChanged()
+ private var lastStep: TransitionStep = TransitionStep()
+
+ /*
+ * When manual control of the transition is requested, a unique [UUID] is used as the handle
+ * to permit calls to [updateTransition]
+ */
+ private var updateTransitionId: UUID? = null
+
+ override fun startTransition(info: TransitionInfo): UUID? {
+ if (lastStep.transitionState != TransitionState.FINISHED) {
+ // Open questions:
+ // * Queue of transitions? buffer of 1?
+ // * Are transitions cancellable if a new one is triggered?
+ // * What validation does this need to do?
+ Log.wtf(TAG, "Transition still active: $lastStep")
+ return null
+ }
+
+ info.animator?.let { animator ->
+ // An animator was provided, so use it to run the transition
+ animator.setFloatValues(0f, 1f)
+ val updateListener =
+ object : AnimatorUpdateListener {
+ override fun onAnimationUpdate(animation: ValueAnimator) {
+ emitTransition(
+ TransitionStep(
+ info,
+ (animation.getAnimatedValue() as Float),
+ TransitionState.RUNNING
+ )
+ )
+ }
+ }
+ val adapter =
+ object : AnimatorListenerAdapter() {
+ override fun onAnimationStart(animation: Animator) {
+ emitTransition(TransitionStep(info, 0f, TransitionState.STARTED))
+ }
+ override fun onAnimationCancel(animation: Animator) {
+ Log.i(TAG, "Cancelling transition: $info")
+ }
+ override fun onAnimationEnd(animation: Animator) {
+ emitTransition(TransitionStep(info, 1f, TransitionState.FINISHED))
+ animator.removeListener(this)
+ animator.removeUpdateListener(updateListener)
+ }
+ }
+ animator.addListener(adapter)
+ animator.addUpdateListener(updateListener)
+ animator.start()
+ return@startTransition null
+ }
+ ?: run {
+ emitTransition(TransitionStep(info, 0f, TransitionState.STARTED))
+
+ // No animator, so it's manual. Provide a mechanism to callback
+ updateTransitionId = UUID.randomUUID()
+ return@startTransition updateTransitionId
+ }
+ }
+
+ override fun updateTransition(
+ transitionId: UUID,
+ @FloatRange(from = 0.0, to = 1.0) value: Float,
+ state: TransitionState
) {
if (updateTransitionId != transitionId) {
Log.wtf(TAG, "Attempting to update with old/invalid transitionId: $transitionId")
return
}
- if (currentTransitionInfo == null) {
- Log.wtf(TAG, "Attempting to update with null 'currentTransitionInfo'")
- return
+ if (state == TransitionState.FINISHED) {
+ updateTransitionId = null
}
- currentTransitionInfo?.let { info ->
- if (state == TransitionState.FINISHED) {
- updateTransitionId = null
- Log.i(TAG, "Ending transition: $info")
- }
-
- emitTransition(info, value, state)
- }
+ val nextStep = lastStep.copy(value = value, transitionState = state)
+ emitTransition(nextStep, isManual = true)
}
- private fun emitTransition(
- info: TransitionInfo,
- value: Float,
- transitionState: TransitionState
- ) {
- trace(info, transitionState)
-
- if (transitionState == TransitionState.FINISHED) {
- currentTransitionInfo = null
+ private fun emitTransition(nextStep: TransitionStep, isManual: Boolean = false) {
+ trace(nextStep, isManual)
+ val emitted = _transitions.tryEmit(nextStep)
+ if (!emitted) {
+ Log.w(TAG, "Failed to emit next value without suspending")
}
- _transitions.value = TransitionStep(info.from, info.to, value, transitionState)
+ lastStep = nextStep
}
- private fun trace(info: TransitionInfo, transitionState: TransitionState) {
+ private fun trace(step: TransitionStep, isManual: Boolean) {
if (
- transitionState != TransitionState.STARTED &&
- transitionState != TransitionState.FINISHED
+ step.transitionState != TransitionState.STARTED &&
+ step.transitionState != TransitionState.FINISHED
) {
return
}
val traceName =
- "Transition: ${info.from} -> ${info.to} " +
- if (info.animator == null) {
+ "Transition: ${step.from} -> ${step.to} " +
+ if (isManual) {
"(manual)"
} else {
""
}
val traceCookie = traceName.hashCode()
- if (transitionState == TransitionState.STARTED) {
+ if (step.transitionState == TransitionState.STARTED) {
Trace.beginAsyncSection(traceName, traceCookie)
- } else if (transitionState == TransitionState.FINISHED) {
+ } else if (step.transitionState == TransitionState.FINISHED) {
Trace.endAsyncSection(traceName, traceCookie)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/AodLockscreenTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/AodLockscreenTransitionInteractor.kt
index 4003766..0aeff7f 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/AodLockscreenTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/AodLockscreenTransitionInteractor.kt
@@ -24,6 +24,7 @@
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionInfo
+import com.android.systemui.util.kotlin.sample
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.collect
@@ -36,31 +37,35 @@
@Application private val scope: CoroutineScope,
private val keyguardRepository: KeyguardRepository,
private val keyguardTransitionRepository: KeyguardTransitionRepository,
+ private val keyguardTransitionInteractor: KeyguardTransitionInteractor,
) : TransitionInteractor("AOD<->LOCKSCREEN") {
override fun start() {
scope.launch {
- keyguardRepository.isDozing.collect { isDozing ->
- if (isDozing) {
- keyguardTransitionRepository.startTransition(
- TransitionInfo(
- name,
- KeyguardState.LOCKSCREEN,
- KeyguardState.AOD,
- getAnimator(),
+ keyguardRepository.isDozing
+ .sample(keyguardTransitionInteractor.finishedKeyguardState, { a, b -> Pair(a, b) })
+ .collect { pair ->
+ val (isDozing, keyguardState) = pair
+ if (isDozing && keyguardState == KeyguardState.LOCKSCREEN) {
+ keyguardTransitionRepository.startTransition(
+ TransitionInfo(
+ name,
+ KeyguardState.LOCKSCREEN,
+ KeyguardState.AOD,
+ getAnimator(),
+ )
)
- )
- } else {
- keyguardTransitionRepository.startTransition(
- TransitionInfo(
- name,
- KeyguardState.AOD,
- KeyguardState.LOCKSCREEN,
- getAnimator(),
+ } else if (!isDozing && keyguardState == KeyguardState.AOD) {
+ keyguardTransitionRepository.startTransition(
+ TransitionInfo(
+ name,
+ KeyguardState.AOD,
+ KeyguardState.LOCKSCREEN,
+ getAnimator(),
+ )
)
- )
+ }
}
- }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/GoneAodTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/GoneAodTransitionInteractor.kt
new file mode 100644
index 0000000..0e2a54c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/GoneAodTransitionInteractor.kt
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.keyguard.domain.interactor
+
+import android.animation.ValueAnimator
+import com.android.systemui.animation.Interpolators
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.shared.model.TransitionInfo
+import com.android.systemui.keyguard.shared.model.WakefulnessModel
+import com.android.systemui.util.kotlin.sample
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.collect
+import kotlinx.coroutines.launch
+
+@SysUISingleton
+class GoneAodTransitionInteractor
+@Inject
+constructor(
+ @Application private val scope: CoroutineScope,
+ private val keyguardInteractor: KeyguardInteractor,
+ private val keyguardTransitionRepository: KeyguardTransitionRepository,
+ private val keyguardTransitionInteractor: KeyguardTransitionInteractor,
+) : TransitionInteractor("GONE->AOD") {
+
+ override fun start() {
+ scope.launch {
+ keyguardInteractor.wakefulnessState
+ .sample(keyguardTransitionInteractor.finishedKeyguardState, { a, b -> Pair(a, b) })
+ .collect { pair ->
+ val (wakefulnessState, keyguardState) = pair
+ if (
+ keyguardState == KeyguardState.GONE &&
+ wakefulnessState == WakefulnessModel.STARTING_TO_SLEEP
+ ) {
+ keyguardTransitionRepository.startTransition(
+ TransitionInfo(
+ name,
+ KeyguardState.GONE,
+ KeyguardState.AOD,
+ getAnimator(),
+ )
+ )
+ }
+ }
+ }
+ }
+
+ private fun getAnimator(): ValueAnimator {
+ return ValueAnimator().apply {
+ setInterpolator(Interpolators.LINEAR)
+ setDuration(TRANSITION_DURATION_MS)
+ }
+ }
+
+ companion object {
+ private const val TRANSITION_DURATION_MS = 500L
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
index fc2269c..03c6a78 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
@@ -19,6 +19,7 @@
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.data.repository.KeyguardRepository
+import com.android.systemui.keyguard.shared.model.WakefulnessModel
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
@@ -40,6 +41,8 @@
val isDozing: Flow<Boolean> = repository.isDozing
/** Whether the keyguard is showing to not. */
val isKeyguardShowing: Flow<Boolean> = repository.isKeyguardShowing
+ /** The device wake/sleep state */
+ val wakefulnessState: Flow<WakefulnessModel> = repository.wakefulnessState
fun isKeyguardShowing(): Boolean {
return repository.isKeyguardShowing()
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionAuditLogger.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionAuditLogger.kt
new file mode 100644
index 0000000..83d9432
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionAuditLogger.kt
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.keyguard.domain.interactor
+
+import com.android.keyguard.logging.KeyguardLogger
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.collect
+import kotlinx.coroutines.launch
+
+/** Collect flows of interest for auditing keyguard transitions. */
+@SysUISingleton
+class KeyguardTransitionAuditLogger
+@Inject
+constructor(
+ @Application private val scope: CoroutineScope,
+ private val interactor: KeyguardTransitionInteractor,
+ private val keyguardInteractor: KeyguardInteractor,
+ private val logger: KeyguardLogger,
+) {
+
+ fun start() {
+ scope.launch {
+ keyguardInteractor.wakefulnessState.collect { logger.v("WakefulnessState", it) }
+ }
+
+ scope.launch {
+ interactor.finishedKeyguardState.collect { logger.i("Finished transition to", it) }
+ }
+
+ scope.launch {
+ interactor.startedKeyguardState.collect { logger.i("Started transition to", it) }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionCoreStartable.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionCoreStartable.kt
index b166681..d5ea77b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionCoreStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionCoreStartable.kt
@@ -26,6 +26,7 @@
@Inject
constructor(
private val interactors: Set<TransitionInteractor>,
+ private val auditLogger: KeyguardTransitionAuditLogger,
) : CoreStartable {
override fun start() {
@@ -38,9 +39,12 @@
when (it) {
is LockscreenBouncerTransitionInteractor -> Log.d(TAG, "Started $it")
is AodLockscreenTransitionInteractor -> Log.d(TAG, "Started $it")
+ is GoneAodTransitionInteractor -> Log.d(TAG, "Started $it")
+ is LockscreenGoneTransitionInteractor -> Log.d(TAG, "Started $it")
}
it.start()
}
+ auditLogger.start()
}
companion object {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
index 7409aec..dffd097 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
@@ -19,11 +19,15 @@
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
+import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.KeyguardState.AOD
+import com.android.systemui.keyguard.shared.model.KeyguardState.GONE
import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN
+import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.shared.model.TransitionStep
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.merge
@@ -40,6 +44,9 @@
/** LOCKSCREEN->AOD transition information. */
val lockscreenToAodTransition: Flow<TransitionStep> = repository.transition(LOCKSCREEN, AOD)
+ /** GONE->AOD information. */
+ val goneToAodTransition: Flow<TransitionStep> = repository.transition(GONE, AOD)
+
/**
* AOD<->LOCKSCREEN transition information, mapped to dozeAmount range of AOD (1f) <->
* Lockscreen (0f).
@@ -49,4 +56,16 @@
aodToLockscreenTransition.map { step -> step.copy(value = 1f - step.value) },
lockscreenToAodTransition,
)
+
+ /* The last completed [KeyguardState] transition */
+ val finishedKeyguardState: Flow<KeyguardState> =
+ repository.transitions
+ .filter { step -> step.transitionState == TransitionState.FINISHED }
+ .map { step -> step.to }
+
+ /* The last started [KeyguardState] transition */
+ val startedKeyguardState: Flow<KeyguardState> =
+ repository.transitions
+ .filter { step -> step.transitionState == TransitionState.STARTED }
+ .map { step -> step.to }
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LockscreenBouncerTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LockscreenBouncerTransitionInteractor.kt
index 3c2a12e..761f3fd 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LockscreenBouncerTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LockscreenBouncerTransitionInteractor.kt
@@ -29,6 +29,7 @@
import java.util.UUID
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.launch
@@ -40,59 +41,63 @@
private val keyguardRepository: KeyguardRepository,
private val shadeRepository: ShadeRepository,
private val keyguardTransitionRepository: KeyguardTransitionRepository,
+ private val keyguardTransitionInteractor: KeyguardTransitionInteractor
) : TransitionInteractor("LOCKSCREEN<->BOUNCER") {
private var transitionId: UUID? = null
override fun start() {
scope.launch {
- shadeRepository.shadeModel.sample(
- combine(
- keyguardTransitionRepository.transitions,
- keyguardRepository.statusBarState,
- ) { transitions, statusBarState ->
- Pair(transitions, statusBarState)
- }
- ) { shadeModel, pair ->
- val (transitions, statusBarState) = pair
+ shadeRepository.shadeModel
+ .sample(
+ combine(
+ keyguardTransitionInteractor.finishedKeyguardState,
+ keyguardRepository.statusBarState,
+ ) { keyguardState, statusBarState ->
+ Pair(keyguardState, statusBarState)
+ },
+ { shadeModel, pair -> Triple(shadeModel, pair.first, pair.second) }
+ )
+ .collect { triple ->
+ val (shadeModel, keyguardState, statusBarState) = triple
- val id = transitionId
- if (id != null) {
- // An existing `id` means a transition is started, and calls to
- // `updateTransition` will control it until FINISHED
- keyguardTransitionRepository.updateTransition(
- id,
- shadeModel.expansionAmount,
- if (shadeModel.expansionAmount == 0f || shadeModel.expansionAmount == 1f) {
- transitionId = null
- TransitionState.FINISHED
- } else {
- TransitionState.RUNNING
- }
- )
- } else {
- // TODO (b/251849525): Remove statusbarstate check when that state is integrated
- // into KeyguardTransitionRepository
- val isOnLockscreen =
- transitions.transitionState == TransitionState.FINISHED &&
- transitions.to == KeyguardState.LOCKSCREEN
- if (
- isOnLockscreen &&
- shadeModel.isUserDragging &&
- statusBarState != SHADE_LOCKED
- ) {
- transitionId =
- keyguardTransitionRepository.startTransition(
- TransitionInfo(
- ownerName = name,
- from = KeyguardState.LOCKSCREEN,
- to = KeyguardState.BOUNCER,
- animator = null,
+ val id = transitionId
+ if (id != null) {
+ // An existing `id` means a transition is started, and calls to
+ // `updateTransition` will control it until FINISHED
+ keyguardTransitionRepository.updateTransition(
+ id,
+ shadeModel.expansionAmount,
+ if (
+ shadeModel.expansionAmount == 0f || shadeModel.expansionAmount == 1f
+ ) {
+ transitionId = null
+ TransitionState.FINISHED
+ } else {
+ TransitionState.RUNNING
+ }
+ )
+ } else {
+ // TODO (b/251849525): Remove statusbarstate check when that state is
+ // integrated
+ // into KeyguardTransitionRepository
+ if (
+ keyguardState == KeyguardState.LOCKSCREEN &&
+ shadeModel.isUserDragging &&
+ statusBarState != SHADE_LOCKED
+ ) {
+ transitionId =
+ keyguardTransitionRepository.startTransition(
+ TransitionInfo(
+ ownerName = name,
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.BOUNCER,
+ animator = null,
+ )
)
- )
+ }
}
}
- }
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LockscreenGoneTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LockscreenGoneTransitionInteractor.kt
new file mode 100644
index 0000000..6c1adbd
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LockscreenGoneTransitionInteractor.kt
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.keyguard.domain.interactor
+
+import android.animation.ValueAnimator
+import com.android.systemui.animation.Interpolators
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.shared.model.TransitionInfo
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.collect
+import kotlinx.coroutines.launch
+
+@SysUISingleton
+class LockscreenGoneTransitionInteractor
+@Inject
+constructor(
+ @Application private val scope: CoroutineScope,
+ private val keyguardInteractor: KeyguardInteractor,
+ private val keyguardTransitionRepository: KeyguardTransitionRepository,
+) : TransitionInteractor("LOCKSCREEN->GONE") {
+
+ override fun start() {
+ scope.launch {
+ keyguardInteractor.isKeyguardShowing.collect { isShowing ->
+ if (!isShowing) {
+ keyguardTransitionRepository.startTransition(
+ TransitionInfo(
+ name,
+ KeyguardState.LOCKSCREEN,
+ KeyguardState.GONE,
+ getAnimator(),
+ )
+ )
+ }
+ }
+ }
+ }
+
+ private fun getAnimator(): ValueAnimator {
+ return ValueAnimator().apply {
+ setInterpolator(Interpolators.LINEAR)
+ setDuration(TRANSITION_DURATION_MS)
+ }
+ }
+
+ companion object {
+ private const val TRANSITION_DURATION_MS = 10L
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/StartKeyguardTransitionModule.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/StartKeyguardTransitionModule.kt
index 74c542c..728bafa 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/StartKeyguardTransitionModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/StartKeyguardTransitionModule.kt
@@ -39,4 +39,10 @@
@Binds
@IntoSet
abstract fun aodLockscreen(impl: AodLockscreenTransitionInteractor): TransitionInteractor
+
+ @Binds @IntoSet abstract fun goneAod(impl: GoneAodTransitionInteractor): TransitionInteractor
+
+ @Binds
+ @IntoSet
+ abstract fun lockscreenGone(impl: LockscreenGoneTransitionInteractor): TransitionInteractor
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/KeyguardState.kt b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/KeyguardState.kt
index f66d5d3..7958033 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/KeyguardState.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/KeyguardState.kt
@@ -17,7 +17,10 @@
/** List of all possible states to transition to/from */
enum class KeyguardState {
- /** For initialization only */
+ /**
+ * For initialization as well as when the security method is set to NONE, indicating that
+ * the keyguard should never be shown.
+ */
NONE,
/* Always-on Display. The device is in a low-power mode with a minimal UI visible */
AOD,
@@ -31,4 +34,11 @@
* unlocked if SWIPE security method is used, or if face lockscreen bypass is false.
*/
LOCKSCREEN,
+
+ /*
+ * Keyguard is no longer visible. In most cases the user has just authenticated and keyguard
+ * is being removed, but there are other cases where the user is swiping away keyguard, such as
+ * with SWIPE security method or face unlock without bypass.
+ */
+ GONE,
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/TransitionState.kt b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/TransitionState.kt
index d8691c1..0e0465b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/TransitionState.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/TransitionState.kt
@@ -17,7 +17,6 @@
/** Possible states for a running transition between [State] */
enum class TransitionState {
- NONE,
STARTED,
RUNNING,
FINISHED
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/TransitionStep.kt b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/TransitionStep.kt
index 688ec91..0ca3582 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/TransitionStep.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/TransitionStep.kt
@@ -20,5 +20,11 @@
val from: KeyguardState = KeyguardState.NONE,
val to: KeyguardState = KeyguardState.NONE,
val value: Float = 0f, // constrained [0.0, 1.0]
- val transitionState: TransitionState = TransitionState.NONE,
-)
+ val transitionState: TransitionState = TransitionState.FINISHED,
+) {
+ constructor(
+ info: TransitionInfo,
+ value: Float,
+ transitionState: TransitionState,
+ ) : this(info.from, info.to, value, transitionState)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/WakefulnessModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/WakefulnessModel.kt
new file mode 100644
index 0000000..64f834d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/WakefulnessModel.kt
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+package com.android.systemui.keyguard.shared.model
+
+/** Model device wakefulness states. */
+enum class WakefulnessModel {
+ /** The device is asleep and not interactive. */
+ ASLEEP,
+ /** Received a signal that the device is beginning to wake up. */
+ STARTING_TO_WAKE,
+ /** Device is now fully awake and interactive. */
+ AWAKE,
+ /** Signal that the device is now going to sleep. */
+ STARTING_TO_SLEEP,
+}
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/models/player/MediaData.kt b/packages/SystemUI/src/com/android/systemui/media/controls/models/player/MediaData.kt
index ed649b1..f006442 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/models/player/MediaData.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/models/player/MediaData.kt
@@ -181,6 +181,7 @@
return enabled == other.enabled &&
name == other.name &&
intent == other.intent &&
- id == other.id
+ id == other.id &&
+ showBroadcastButton == other.showBroadcastButton
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/models/player/MediaViewHolder.kt b/packages/SystemUI/src/com/android/systemui/media/controls/models/player/MediaViewHolder.kt
index 2511324..a7f1b95 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/models/player/MediaViewHolder.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/models/player/MediaViewHolder.kt
@@ -26,6 +26,7 @@
import androidx.constraintlayout.widget.Barrier
import com.android.systemui.R
import com.android.systemui.media.controls.models.GutsViewHolder
+import com.android.systemui.ripple.MultiRippleView
import com.android.systemui.util.animation.TransitionLayout
private const val TAG = "MediaViewHolder"
@@ -36,6 +37,7 @@
// Player information
val albumView = itemView.requireViewById<ImageView>(R.id.album_art)
+ val multiRippleView = itemView.requireViewById<MultiRippleView>(R.id.touch_ripple_view)
val appIcon = itemView.requireViewById<ImageView>(R.id.icon)
val titleText = itemView.requireViewById<TextView>(R.id.header_title)
val artistText = itemView.requireViewById<TextView>(R.id.header_artist)
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/ColorSchemeTransition.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/ColorSchemeTransition.kt
index 61ef2f1..918417f 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/ColorSchemeTransition.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/ColorSchemeTransition.kt
@@ -29,6 +29,7 @@
import com.android.settingslib.Utils
import com.android.systemui.media.controls.models.player.MediaViewHolder
import com.android.systemui.monet.ColorScheme
+import com.android.systemui.ripple.MultiRippleController
/**
* A [ColorTransition] is an object that updates the colors of views each time [updateColorScheme]
@@ -100,12 +101,14 @@
internal constructor(
private val context: Context,
private val mediaViewHolder: MediaViewHolder,
+ private val multiRippleController: MultiRippleController,
animatingColorTransitionFactory: AnimatingColorTransitionFactory
) {
constructor(
context: Context,
- mediaViewHolder: MediaViewHolder
- ) : this(context, mediaViewHolder, ::AnimatingColorTransition)
+ mediaViewHolder: MediaViewHolder,
+ multiRippleController: MultiRippleController,
+ ) : this(context, mediaViewHolder, multiRippleController, ::AnimatingColorTransition)
val bgColor = context.getColor(com.android.systemui.R.color.material_dynamic_secondary95)
val surfaceColor =
@@ -125,6 +128,7 @@
val accentColorList = ColorStateList.valueOf(accentPrimary)
mediaViewHolder.actionPlayPause.backgroundTintList = accentColorList
mediaViewHolder.gutsViewHolder.setAccentPrimaryColor(accentPrimary)
+ multiRippleController.updateColor(accentPrimary)
}
val accentSecondary =
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java
index 18ecadb..5b14cf3 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java
@@ -76,6 +76,8 @@
import com.android.systemui.broadcast.BroadcastSender;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.flags.Flags;
import com.android.systemui.media.controls.models.GutsViewHolder;
import com.android.systemui.media.controls.models.player.MediaAction;
import com.android.systemui.media.controls.models.player.MediaButton;
@@ -95,6 +97,10 @@
import com.android.systemui.monet.Style;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.FalsingManager;
+import com.android.systemui.ripple.MultiRippleController;
+import com.android.systemui.ripple.RippleAnimation;
+import com.android.systemui.ripple.RippleAnimationConfig;
+import com.android.systemui.ripple.RippleShader;
import com.android.systemui.shared.system.SysUiStatsLog;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -209,6 +215,8 @@
private boolean mIsCurrentBroadcastedApp = false;
private boolean mShowBroadcastDialogButton = false;
private String mSwitchBroadcastApp;
+ private MultiRippleController mMultiRippleController;
+ private FeatureFlags mFeatureFlags;
/**
* Initialize a new control panel
@@ -236,7 +244,9 @@
KeyguardStateController keyguardStateController,
ActivityIntentHelper activityIntentHelper,
NotificationLockscreenUserManager lockscreenUserManager,
- BroadcastDialogController broadcastDialogController) {
+ BroadcastDialogController broadcastDialogController,
+ FeatureFlags featureFlags
+ ) {
mContext = context;
mBackgroundExecutor = backgroundExecutor;
mMainExecutor = mainExecutor;
@@ -262,6 +272,8 @@
logSmartspaceCardReported(SMARTSPACE_CARD_CLICK_EVENT);
return Unit.INSTANCE;
});
+
+ mFeatureFlags = featureFlags;
}
/**
@@ -381,7 +393,9 @@
AnimatorSet exit = loadAnimator(R.anim.media_metadata_exit,
Interpolators.EMPHASIZED_ACCELERATE, titleText, artistText);
- mColorSchemeTransition = new ColorSchemeTransition(mContext, mMediaViewHolder);
+ mMultiRippleController = new MultiRippleController(vh.getMultiRippleView());
+ mColorSchemeTransition = new ColorSchemeTransition(
+ mContext, mMediaViewHolder, mMultiRippleController);
mMetadataAnimationHandler = new MetadataAnimationHandler(exit, enter);
}
@@ -982,6 +996,9 @@
mLogger.logTapAction(button.getId(), mUid, mPackageName, mInstanceId);
logSmartspaceCardReported(SMARTSPACE_CARD_CLICK_EVENT);
action.run();
+ if (mFeatureFlags.isEnabled(Flags.UMO_SURFACE_RIPPLE)) {
+ mMultiRippleController.play(createTouchRippleAnimation(button));
+ }
if (icon instanceof Animatable) {
((Animatable) icon).start();
@@ -997,6 +1014,26 @@
}
}
+ private RippleAnimation createTouchRippleAnimation(ImageButton button) {
+ float maxSize = mMediaViewHolder.getMultiRippleView().getWidth() * 2;
+ return new RippleAnimation(
+ new RippleAnimationConfig(
+ RippleShader.RippleShape.CIRCLE,
+ /* duration= */ 1500L,
+ /* centerX= */ button.getX() + button.getWidth() * 0.5f,
+ /* centerY= */ button.getY() + button.getHeight() * 0.5f,
+ /* maxWidth= */ maxSize,
+ /* maxHeight= */ maxSize,
+ /* pixelDensity= */ getContext().getResources().getDisplayMetrics().density,
+ mColorSchemeTransition.getAccentPrimary().getTargetColor(),
+ /* opacity= */ 100,
+ /* shouldFillRipple= */ false,
+ /* sparkleStrength= */ 0f,
+ /* shouldDistort= */ false
+ )
+ );
+ }
+
private void clearButton(final ImageButton button) {
button.setImageDrawable(null);
button.setContentDescription(null);
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt
index 7dd9fb4..662d059 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt
@@ -189,7 +189,7 @@
}
private fun startRipple(rippleView: ReceiverChipRippleView) {
- if (rippleView.rippleInProgress) {
+ if (rippleView.rippleInProgress()) {
// Skip if ripple is still playing
return
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrier.java b/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrier.java
index 703b95a..b5ceeae 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrier.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/carrier/QSCarrier.java
@@ -19,6 +19,7 @@
import android.annotation.StyleRes;
import android.content.Context;
import android.content.res.ColorStateList;
+import android.content.res.Configuration;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.View;
@@ -33,6 +34,7 @@
import com.android.settingslib.graph.SignalDrawable;
import com.android.systemui.FontSizeUtils;
import com.android.systemui.R;
+import com.android.systemui.util.LargeScreenUtils;
import java.util.Objects;
@@ -72,6 +74,7 @@
mMobileSignal = findViewById(R.id.mobile_signal);
mCarrierText = findViewById(R.id.qs_carrier_text);
mSpacer = findViewById(R.id.spacer);
+ updateResources();
}
/**
@@ -142,4 +145,20 @@
public void updateTextAppearance(@StyleRes int resId) {
FontSizeUtils.updateFontSizeFromStyle(mCarrierText, resId);
}
+
+ @Override
+ protected void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+ updateResources();
+ }
+
+ private void updateResources() {
+ boolean useLargeScreenHeader =
+ LargeScreenUtils.shouldUseLargeScreenShadeHeader(getResources());
+ mCarrierText.setMaxEms(
+ useLargeScreenHeader
+ ? Integer.MAX_VALUE
+ : getResources().getInteger(R.integer.qs_carrier_max_em)
+ );
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/ripple/MultiRippleController.kt b/packages/SystemUI/src/com/android/systemui/ripple/MultiRippleController.kt
new file mode 100644
index 0000000..48df15c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/ripple/MultiRippleController.kt
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.ripple
+
+import androidx.annotation.VisibleForTesting
+
+/** Controller that handles playing [RippleAnimation]. */
+class MultiRippleController(private val multipleRippleView: MultiRippleView) {
+
+ companion object {
+ /** Max number of ripple animations at a time. */
+ @VisibleForTesting const val MAX_RIPPLE_NUMBER = 10
+ }
+
+ /** Updates all the ripple colors during the animation. */
+ fun updateColor(color: Int) {
+ multipleRippleView.ripples.forEach { anim -> anim.updateColor(color) }
+ }
+
+ fun play(rippleAnimation: RippleAnimation) {
+ if (multipleRippleView.ripples.size >= MAX_RIPPLE_NUMBER) {
+ return
+ }
+
+ multipleRippleView.ripples.add(rippleAnimation)
+
+ // Remove ripple once the animation is done
+ rippleAnimation.play { multipleRippleView.ripples.remove(rippleAnimation) }
+
+ // Trigger drawing
+ multipleRippleView.invalidate()
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/ripple/MultiRippleView.kt b/packages/SystemUI/src/com/android/systemui/ripple/MultiRippleView.kt
new file mode 100644
index 0000000..c7f0b7e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/ripple/MultiRippleView.kt
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.ripple
+
+import android.content.Context
+import android.graphics.Canvas
+import android.graphics.Paint
+import android.util.AttributeSet
+import android.util.Log
+import android.view.View
+
+/**
+ * A view that allows multiple ripples to play.
+ *
+ * Use [MultiRippleController] to play ripple animations.
+ */
+class MultiRippleView(context: Context?, attrs: AttributeSet?) : View(context, attrs) {
+
+ internal val ripples = ArrayList<RippleAnimation>()
+ private val ripplePaint = Paint()
+ private var isWarningLogged = false
+
+ companion object {
+ const val TAG = "MultiRippleView"
+ }
+
+ override fun onDraw(canvas: Canvas?) {
+ if (canvas == null || !canvas.isHardwareAccelerated) {
+ // Drawing with the ripple shader requires hardware acceleration, so skip
+ // if it's unsupported.
+ if (!isWarningLogged) {
+ // Only log once to not spam.
+ Log.w(
+ TAG,
+ "Can't draw ripple shader. $canvas does not support hardware acceleration."
+ )
+ isWarningLogged = true
+ }
+ return
+ }
+
+ var shouldInvalidate = false
+
+ ripples.forEach { anim ->
+ ripplePaint.shader = anim.rippleShader
+ canvas.drawPaint(ripplePaint)
+
+ shouldInvalidate = shouldInvalidate || anim.isPlaying()
+ }
+
+ if (shouldInvalidate) invalidate()
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/ripple/RippleAnimation.kt b/packages/SystemUI/src/com/android/systemui/ripple/RippleAnimation.kt
new file mode 100644
index 0000000..aca9e25
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/ripple/RippleAnimation.kt
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.ripple
+
+import android.animation.Animator
+import android.animation.AnimatorListenerAdapter
+import android.animation.ValueAnimator
+import androidx.core.graphics.ColorUtils
+
+/** A single ripple animation. */
+class RippleAnimation(private val config: RippleAnimationConfig) {
+ internal val rippleShader: RippleShader = RippleShader(config.rippleShape)
+ private val animator: ValueAnimator = ValueAnimator.ofFloat(0f, 1f)
+
+ init {
+ applyConfigToShader()
+ }
+
+ /** Updates the ripple color during the animation. */
+ fun updateColor(color: Int) {
+ config.apply { config.color = color }
+ applyConfigToShader()
+ }
+
+ @JvmOverloads
+ fun play(onAnimationEnd: Runnable? = null) {
+ if (isPlaying()) {
+ return // Ignore if ripple effect is already playing
+ }
+
+ animator.duration = config.duration
+ animator.addUpdateListener { updateListener ->
+ val now = updateListener.currentPlayTime
+ val progress = updateListener.animatedValue as Float
+ rippleShader.progress = progress
+ rippleShader.distortionStrength = if (config.shouldDistort) 1 - progress else 0f
+ rippleShader.time = now.toFloat()
+ }
+ animator.addListener(
+ object : AnimatorListenerAdapter() {
+ override fun onAnimationEnd(animation: Animator?) {
+ onAnimationEnd?.run()
+ }
+ }
+ )
+ animator.start()
+ }
+
+ /** Indicates whether the animation is playing. */
+ fun isPlaying(): Boolean = animator.isRunning
+
+ private fun applyConfigToShader() {
+ rippleShader.setCenter(config.centerX, config.centerY)
+ rippleShader.setMaxSize(config.maxWidth, config.maxHeight)
+ rippleShader.rippleFill = config.shouldFillRipple
+ rippleShader.pixelDensity = config.pixelDensity
+ rippleShader.color = ColorUtils.setAlphaComponent(config.color, config.opacity)
+ rippleShader.sparkleStrength = config.sparkleStrength
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/ripple/RippleAnimationConfig.kt b/packages/SystemUI/src/com/android/systemui/ripple/RippleAnimationConfig.kt
new file mode 100644
index 0000000..8812254
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/ripple/RippleAnimationConfig.kt
@@ -0,0 +1,32 @@
+package com.android.systemui.ripple
+
+import android.graphics.Color
+
+/**
+ * A struct that holds the ripple animation configurations.
+ *
+ * <p>This configuration is designed to play a SINGLE animation. Do not reuse or modify the
+ * configuration parameters to play different animations, unless the value has to change within the
+ * single animation (e.g. Change color or opacity during the animation). Note that this data class
+ * is pulled out to make the [RippleAnimation] constructor succinct.
+ */
+data class RippleAnimationConfig(
+ val rippleShape: RippleShader.RippleShape = RippleShader.RippleShape.CIRCLE,
+ val duration: Long = 0L,
+ val centerX: Float = 0f,
+ val centerY: Float = 0f,
+ val maxWidth: Float = 0f,
+ val maxHeight: Float = 0f,
+ val pixelDensity: Float = 1f,
+ var color: Int = Color.WHITE,
+ val opacity: Int = RIPPLE_DEFAULT_ALPHA,
+ val shouldFillRipple: Boolean = false,
+ val sparkleStrength: Float = RIPPLE_SPARKLE_STRENGTH,
+ val shouldDistort: Boolean = true
+) {
+ companion object {
+ const val RIPPLE_SPARKLE_STRENGTH: Float = 0.3f
+ const val RIPPLE_DEFAULT_COLOR: Int = 0xffffffff.toInt()
+ const val RIPPLE_DEFAULT_ALPHA: Int = 45 // full opacity is 255.
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/ripple/RippleView.kt b/packages/SystemUI/src/com/android/systemui/ripple/RippleView.kt
index 1e51ffa..a6d7930 100644
--- a/packages/SystemUI/src/com/android/systemui/ripple/RippleView.kt
+++ b/packages/SystemUI/src/com/android/systemui/ripple/RippleView.kt
@@ -28,10 +28,6 @@
import androidx.core.graphics.ColorUtils
import com.android.systemui.ripple.RippleShader.RippleShape
-private const val RIPPLE_SPARKLE_STRENGTH: Float = 0.3f
-private const val RIPPLE_DEFAULT_COLOR: Int = 0xffffffff.toInt()
-const val RIPPLE_DEFAULT_ALPHA: Int = 45
-
/**
* A generic expanding ripple effect.
*
@@ -45,8 +41,8 @@
private set
private val ripplePaint = Paint()
+ private val animator = ValueAnimator.ofFloat(0f, 1f)
- var rippleInProgress: Boolean = false
var duration: Long = 1750
private var maxWidth: Float = 0.0f
@@ -80,9 +76,9 @@
this.rippleShape = rippleShape
rippleShader = RippleShader(rippleShape)
- rippleShader.color = RIPPLE_DEFAULT_COLOR
+ rippleShader.color = RippleAnimationConfig.RIPPLE_DEFAULT_COLOR
rippleShader.progress = 0f
- rippleShader.sparkleStrength = RIPPLE_SPARKLE_STRENGTH
+ rippleShader.sparkleStrength = RippleAnimationConfig.RIPPLE_SPARKLE_STRENGTH
rippleShader.pixelDensity = resources.displayMetrics.density
ripplePaint.shader = rippleShader
@@ -90,10 +86,9 @@
@JvmOverloads
fun startRipple(onAnimationEnd: Runnable? = null) {
- if (rippleInProgress) {
+ if (animator.isRunning) {
return // Ignore if ripple effect is already playing
}
- val animator = ValueAnimator.ofFloat(0f, 1f)
animator.duration = duration
animator.addUpdateListener { updateListener ->
val now = updateListener.currentPlayTime
@@ -105,19 +100,17 @@
}
animator.addListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator?) {
- rippleInProgress = false
onAnimationEnd?.run()
}
})
animator.start()
- rippleInProgress = true
}
/** Set the color to be used for the ripple.
*
* The alpha value of the color will be applied to the ripple. The alpha range is [0-100].
*/
- fun setColor(color: Int, alpha: Int = RIPPLE_DEFAULT_ALPHA) {
+ fun setColor(color: Int, alpha: Int = RippleAnimationConfig.RIPPLE_DEFAULT_ALPHA) {
rippleShader.color = ColorUtils.setAlphaComponent(color, alpha)
}
@@ -137,6 +130,9 @@
rippleShader.sparkleStrength = strength
}
+ /** Indicates whether the ripple animation is playing. */
+ fun rippleInProgress(): Boolean = animator.isRunning
+
override fun onDraw(canvas: Canvas?) {
if (canvas == null || !canvas.isHardwareAccelerated) {
// Drawing with the ripple shader requires hardware acceleration, so skip
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ImageExporter.java b/packages/SystemUI/src/com/android/systemui/screenshot/ImageExporter.java
index e3658de..c8c1337 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ImageExporter.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ImageExporter.java
@@ -38,6 +38,8 @@
import androidx.exifinterface.media.ExifInterface;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.flags.Flags;
import com.google.common.util.concurrent.ListenableFuture;
@@ -85,10 +87,12 @@
private final ContentResolver mResolver;
private CompressFormat mCompressFormat = CompressFormat.PNG;
private int mQuality = 100;
+ private final FeatureFlags mFlags;
@Inject
- ImageExporter(ContentResolver resolver) {
+ ImageExporter(ContentResolver resolver, FeatureFlags flags) {
mResolver = resolver;
+ mFlags = flags;
}
/**
@@ -161,7 +165,7 @@
ZonedDateTime captureTime, UserHandle owner) {
final Task task = new Task(mResolver, requestId, bitmap, captureTime, mCompressFormat,
- mQuality, /* publish */ true, owner);
+ mQuality, /* publish */ true, owner, mFlags);
return CallbackToFutureAdapter.getFuture(
(completer) -> {
@@ -209,9 +213,11 @@
private final UserHandle mOwner;
private final String mFileName;
private final boolean mPublish;
+ private final FeatureFlags mFlags;
Task(ContentResolver resolver, UUID requestId, Bitmap bitmap, ZonedDateTime captureTime,
- CompressFormat format, int quality, boolean publish, UserHandle owner) {
+ CompressFormat format, int quality, boolean publish, UserHandle owner,
+ FeatureFlags flags) {
mResolver = resolver;
mRequestId = requestId;
mBitmap = bitmap;
@@ -221,6 +227,7 @@
mOwner = owner;
mFileName = createFilename(mCaptureTime, mFormat);
mPublish = publish;
+ mFlags = flags;
}
public Result execute() throws ImageExportException, InterruptedException {
@@ -234,7 +241,7 @@
start = Instant.now();
}
- uri = createEntry(mResolver, mFormat, mCaptureTime, mFileName, mOwner);
+ uri = createEntry(mResolver, mFormat, mCaptureTime, mFileName, mOwner, mFlags);
throwIfInterrupted();
writeImage(mResolver, mBitmap, mFormat, mQuality, uri);
@@ -278,13 +285,15 @@
}
private static Uri createEntry(ContentResolver resolver, CompressFormat format,
- ZonedDateTime time, String fileName, UserHandle owner) throws ImageExportException {
+ ZonedDateTime time, String fileName, UserHandle owner, FeatureFlags flags)
+ throws ImageExportException {
Trace.beginSection("ImageExporter_createEntry");
try {
final ContentValues values = createMetadata(time, format, fileName);
Uri baseUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
- if (UserHandle.myUserId() != owner.getIdentifier()) {
+ if (flags.isEnabled(Flags.SCREENSHOT_WORK_PROFILE_POLICY)
+ && UserHandle.myUserId() != owner.getIdentifier()) {
baseUri = ContentProvider.maybeAddUserId(baseUri, owner.getIdentifier());
}
Uri uri = resolver.insert(baseUri, values);
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
index d524a35..9b5295d 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
@@ -1043,8 +1043,13 @@
}
private boolean isUserSetupComplete(UserHandle owner) {
- return Settings.Secure.getInt(mContext.createContextAsUser(owner, 0)
- .getContentResolver(), SETTINGS_SECURE_USER_SETUP_COMPLETE, 0) == 1;
+ if (mFlags.isEnabled(SCREENSHOT_WORK_PROFILE_POLICY)) {
+ return Settings.Secure.getInt(mContext.createContextAsUser(owner, 0)
+ .getContentResolver(), SETTINGS_SECURE_USER_SETUP_COMPLETE, 0) == 1;
+ } else {
+ return Settings.Secure.getInt(mContext.getContentResolver(),
+ SETTINGS_SECURE_USER_SETUP_COMPLETE, 0) == 1;
+ }
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt b/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt
index 6711734..cd5647e 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt
@@ -30,7 +30,6 @@
import androidx.annotation.WorkerThread
import com.android.systemui.Dumpable
import com.android.systemui.dump.DumpManager
-import com.android.systemui.people.widget.PeopleSpaceWidgetProvider.EXTRA_USER_HANDLE
import com.android.systemui.util.Assert
import java.io.PrintWriter
import java.lang.ref.WeakReference
@@ -53,7 +52,7 @@
*
* Class constructed and initialized in [SettingsModule].
*/
-class UserTrackerImpl internal constructor(
+open class UserTrackerImpl internal constructor(
private val context: Context,
private val userManager: UserManager,
private val dumpManager: DumpManager,
@@ -70,13 +69,13 @@
private val mutex = Any()
override var userId: Int by SynchronizedDelegate(context.userId)
- private set
+ protected set
override var userHandle: UserHandle by SynchronizedDelegate(context.user)
- private set
+ protected set
override var userContext: Context by SynchronizedDelegate(context)
- private set
+ protected set
override val userContentResolver: ContentResolver
get() = userContext.contentResolver
@@ -94,7 +93,7 @@
* modified.
*/
override var userProfiles: List<UserInfo> by SynchronizedDelegate(emptyList())
- private set
+ protected set
@GuardedBy("callbacks")
private val callbacks: MutableList<DataItem> = ArrayList()
@@ -155,7 +154,7 @@
}
@WorkerThread
- private fun handleSwitchUser(newUser: Int) {
+ protected open fun handleSwitchUser(newUser: Int) {
Assert.isNotMainThread()
if (newUser == UserHandle.USER_NULL) {
Log.w(TAG, "handleSwitchUser - Couldn't get new id from intent")
@@ -174,7 +173,7 @@
}
@WorkerThread
- private fun handleProfilesChanged() {
+ protected open fun handleProfilesChanged() {
Assert.isNotMainThread()
val profiles = userManager.getProfiles(userId)
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index 1c0f057..2450197 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -33,7 +33,6 @@
import static com.android.systemui.classifier.Classifier.QS_COLLAPSE;
import static com.android.systemui.classifier.Classifier.QUICK_SETTINGS;
import static com.android.systemui.classifier.Classifier.UNLOCK;
-import static com.android.systemui.shade.NotificationPanelView.DEBUG;
import static com.android.systemui.shade.ShadeExpansionStateManagerKt.STATE_CLOSED;
import static com.android.systemui.shade.ShadeExpansionStateManagerKt.STATE_OPEN;
import static com.android.systemui.shade.ShadeExpansionStateManagerKt.STATE_OPENING;
@@ -41,9 +40,7 @@
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_QUICK_SETTINGS_EXPANDED;
import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
import static com.android.systemui.statusbar.StatusBarState.SHADE;
-import static com.android.systemui.statusbar.StatusBarState.SHADE_LOCKED;
import static com.android.systemui.statusbar.VibratorHelper.TOUCH_VIBRATION_ATTRIBUTES;
-import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.ROWS_ALL;
import static com.android.systemui.statusbar.notification.stack.StackStateAnimator.ANIMATION_DURATION_FOLD_TO_AOD;
import static com.android.systemui.util.DumpUtilsKt.asIndenting;
@@ -53,10 +50,10 @@
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.Fragment;
import android.app.StatusBarManager;
import android.content.ContentResolver;
-import android.content.res.Configuration;
import android.content.res.Resources;
import android.database.ContentObserver;
import android.graphics.Canvas;
@@ -104,7 +101,6 @@
import android.view.animation.Interpolator;
import android.widget.FrameLayout;
-import androidx.annotation.Nullable;
import androidx.constraintlayout.widget.ConstraintSet;
import com.android.internal.annotations.VisibleForTesting;
@@ -175,16 +171,13 @@
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.VibratorHelper;
-import com.android.systemui.statusbar.events.PrivacyDotViewController;
import com.android.systemui.statusbar.notification.AnimatableProperty;
import com.android.systemui.statusbar.notification.ConversationNotificationManager;
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
import com.android.systemui.statusbar.notification.PropertyAnimator;
import com.android.systemui.statusbar.notification.ViewGroupFadeHelper;
-import com.android.systemui.statusbar.notification.collection.ListEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.notification.collection.render.ShadeViewManager;
import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.ExpandableView;
@@ -210,7 +203,6 @@
import com.android.systemui.statusbar.phone.KeyguardStatusBarViewController;
import com.android.systemui.statusbar.phone.LockscreenGestureLogger;
import com.android.systemui.statusbar.phone.LockscreenGestureLogger.LockscreenUiEvent;
-import com.android.systemui.statusbar.phone.NotificationIconAreaController;
import com.android.systemui.statusbar.phone.PhoneStatusBarView;
import com.android.systemui.statusbar.phone.ScreenOffAnimationController;
import com.android.systemui.statusbar.phone.ScrimController;
@@ -257,28 +249,15 @@
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
- */
+ /** The parallax amount of the quick settings translation when dragging down the panel. */
private static final float QS_PARALLAX_AMOUNT = 0.175f;
-
- /**
- * Fling expanding QS.
- */
+ /** Fling expanding QS. */
public static final int FLING_EXPAND = 0;
-
- /**
- * Fling collapsing QS, potentially stopping when QS becomes QQS.
- */
+ /** Fling collapsing QS, potentially stopping when QS becomes QQS. */
private static final int FLING_COLLAPSE = 1;
-
- /**
- * Fling until QS is completely hidden.
- */
+ /** Fling until QS is completely hidden. */
private static final int FLING_HIDE = 2;
private static final long ANIMATION_DELAY_ICON_FADE_IN =
ActivityLaunchAnimator.TIMINGS.getTotalDuration()
@@ -292,6 +271,18 @@
* when flinging. A low value will make it that most flings will reach the maximum overshoot.
*/
private static final float FACTOR_OF_HIGH_VELOCITY_FOR_MAX_OVERSHOOT = 0.5f;
+ /**
+ * Maximum time before which we will expand the panel even for slow motions when getting a
+ * touch passed over from launcher.
+ */
+ private static final int MAX_TIME_TO_OPEN_WHEN_FLINGING_FROM_LAUNCHER = 300;
+ private static final int MAX_DOWN_EVENT_BUFFER_SIZE = 50;
+ private static final String COUNTER_PANEL_OPEN = "panel_open";
+ private static final String COUNTER_PANEL_OPEN_QS = "panel_open_qs";
+ private static final String COUNTER_PANEL_OPEN_PEEK = "panel_open_peek";
+ private static final Rect M_DUMMY_DIRTY_RECT = new Rect(0, 0, 1, 1);
+ private static final Rect EMPTY_RECT = new Rect();
+
private final StatusBarTouchableRegionManager mStatusBarTouchableRegionManager;
private final Resources mResources;
private final KeyguardStateController mKeyguardStateController;
@@ -300,49 +291,24 @@
private final LockscreenGestureLogger mLockscreenGestureLogger;
private final SystemClock mSystemClock;
private final ShadeLogger mShadeLog;
-
private final DozeParameters mDozeParameters;
- private final OnHeightChangedListener mOnHeightChangedListener = new OnHeightChangedListener();
- private final Runnable mCollapseExpandAction = new CollapseExpandAction();
- private final OnOverscrollTopChangedListener
- mOnOverscrollTopChangedListener =
- new OnOverscrollTopChangedListener();
- private final OnEmptySpaceClickListener
- mOnEmptySpaceClickListener =
- new OnEmptySpaceClickListener();
- private final MyOnHeadsUpChangedListener
- mOnHeadsUpChangedListener =
- new MyOnHeadsUpChangedListener();
- private final HeightListener mHeightListener = new HeightListener();
+ private final Runnable mCollapseExpandAction = this::collapseOrExpand;
+ private final NsslOverscrollTopChangedListener mOnOverscrollTopChangedListener =
+ new NsslOverscrollTopChangedListener();
+ private final NotificationStackScrollLayout.OnEmptySpaceClickListener
+ mOnEmptySpaceClickListener = (x, y) -> onEmptySpaceClick();
+ private final ShadeHeadsUpChangedListener mOnHeadsUpChangedListener =
+ new ShadeHeadsUpChangedListener();
+ private final QS.HeightListener mHeightListener = this::onQsHeightChanged;
private final ConfigurationListener mConfigurationListener = new ConfigurationListener();
private final SettingsChangeObserver mSettingsChangeObserver;
-
- @VisibleForTesting
- final StatusBarStateListener mStatusBarStateListener =
- new StatusBarStateListener();
+ private final StatusBarStateListener mStatusBarStateListener = new StatusBarStateListener();
private final NotificationPanelView mView;
private final VibratorHelper mVibratorHelper;
private final MetricsLogger mMetricsLogger;
private final ConfigurationController mConfigurationController;
private final Provider<FlingAnimationUtils.Builder> mFlingAnimationUtilsBuilder;
private final NotificationStackScrollLayoutController mNotificationStackScrollLayoutController;
- private final NotificationIconAreaController mNotificationIconAreaController;
-
- /**
- * Maximum time before which we will expand the panel even for slow motions when getting a
- * touch passed over from launcher.
- */
- private static final int MAX_TIME_TO_OPEN_WHEN_FLINGING_FROM_LAUNCHER = 300;
-
- private static final int MAX_DOWN_EVENT_BUFFER_SIZE = 50;
-
- private static final String COUNTER_PANEL_OPEN = "panel_open";
- private static final String COUNTER_PANEL_OPEN_QS = "panel_open_qs";
- private static final String COUNTER_PANEL_OPEN_PEEK = "panel_open_peek";
-
- private static final Rect M_DUMMY_DIRTY_RECT = new Rect(0, 0, 1, 1);
- private static final Rect EMPTY_RECT = new Rect();
-
private final InteractionJankMonitor mInteractionJankMonitor;
private final LayoutInflater mLayoutInflater;
private final FeatureFlags mFeatureFlags;
@@ -362,9 +328,7 @@
private final KeyguardStatusBarViewComponent.Factory mKeyguardStatusBarViewComponentFactory;
private final FragmentService mFragmentService;
private final ScrimController mScrimController;
- private final PrivacyDotViewController mPrivacyDotViewController;
private final NotificationRemoteInputManager mRemoteInputManager;
-
private final LockscreenShadeTransitionController mLockscreenShadeTransitionController;
private final ShadeTransitionController mShadeTransitionController;
private final TapAgainViewController mTapAgainViewController;
@@ -381,6 +345,11 @@
private final Interpolator mBounceInterpolator;
private final NotificationShadeWindowController mNotificationShadeWindowController;
private final ShadeExpansionStateManager mShadeExpansionStateManager;
+ private final QS.ScrollListener mQsScrollListener = this::onQsPanelScrollChanged;
+ private final FalsingTapListener mFalsingTapListener = this::falsingAdditionalTapRequired;
+ private final FragmentListener mQsFragmentListener = new QsFragmentListener();
+ private final AccessibilityDelegate mAccessibilityDelegate = new ShadeAccessibilityDelegate();
+
private long mDownTime;
private boolean mTouchSlopExceededBeforeDown;
private boolean mIsLaunchAnimationRunning;
@@ -402,13 +371,11 @@
private float mKeyguardNotificationTopPadding;
/** Current max allowed keyguard notifications determined by measuring the panel. */
private int mMaxAllowedKeyguardNotifications;
-
private KeyguardQsUserSwitchController mKeyguardQsUserSwitchController;
private KeyguardUserSwitcherController mKeyguardUserSwitcherController;
private KeyguardStatusBarView mKeyguardStatusBar;
private KeyguardStatusBarViewController mKeyguardStatusBarViewController;
- @VisibleForTesting
- QS mQs;
+ private QS mQs;
private FrameLayout mQsFrame;
private final QsFrameTranslateController mQsFrameTranslateController;
private KeyguardStatusViewController mKeyguardStatusViewController;
@@ -421,18 +388,11 @@
private float mQuickQsHeaderHeight;
private final ScreenOffAnimationController mScreenOffAnimationController;
private final UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController;
-
private int mQsTrackingPointer;
private VelocityTracker mQsVelocityTracker;
private boolean mQsTracking;
-
- /**
- * If set, the ongoing touch gesture might both trigger the expansion in {@link
- * NotificationPanelView} and
- * the expansion for quick settings.
- */
+ /** Whether the ongoing gesture might both trigger the expansion in both the view and QS. */
private boolean mConflictingQsExpansionGesture;
-
private boolean mPanelExpanded;
/**
@@ -487,11 +447,9 @@
* Used for split shade, two finger gesture as well as accessibility shortcut to QS.
* It needs to be set when movement starts as it resets at the end of expansion/collapse.
*/
- @VisibleForTesting
- boolean mQsExpandImmediate;
+ private boolean mQsExpandImmediate;
private boolean mTwoFingerQsExpandPossible;
private String mHeaderDebugInfo;
-
/**
* If we are in a panel collapsing motion, we reset scrollY of our scroll view but still
* need to take this into account in our panel height calculation.
@@ -499,7 +457,6 @@
private boolean mQsAnimatorExpand;
private boolean mIsLaunchTransitionFinished;
private ValueAnimator mQsSizeChangeAnimator;
-
private boolean mQsScrimEnabled = true;
private boolean mQsTouchAboveFalsingThreshold;
private int mQsFalsingThreshold;
@@ -517,39 +474,27 @@
private final FalsingManager mFalsingManager;
private final FalsingCollector mFalsingCollector;
- private final Runnable mHeadsUpExistenceChangedRunnable = () -> {
- setHeadsUpAnimatingAway(false);
- updatePanelExpansionAndVisibility();
- };
private boolean mShowIconsWhenExpanded;
private int mIndicationBottomPadding;
private int mAmbientIndicationBottomPadding;
+ /** Whether the notifications are displayed full width (no margins on the side). */
private boolean mIsFullWidth;
private boolean mBlockingExpansionForCurrentTouch;
+ // Following variables maintain state of events when input focus transfer may occur.
+ private boolean mExpectingSynthesizedDown;
+ private boolean mLastEventSynthesizedDown;
- /**
- * Following variables maintain state of events when input focus transfer may occur.
- */
- private boolean mExpectingSynthesizedDown; // expecting to see synthesized DOWN event
- private boolean mLastEventSynthesizedDown; // last event was synthesized DOWN event
-
- /**
- * Current dark amount that follows regular interpolation curve of animation.
- */
+ /** Current dark amount that follows regular interpolation curve of animation. */
private float mInterpolatedDarkAmount;
-
/**
* Dark amount that animates from 0 to 1 or vice-versa in linear manner, even if the
* interpolation curve is different.
*/
private float mLinearDarkAmount;
-
private boolean mPulsing;
private boolean mHideIconsDuringLaunchAnimation = true;
private int mStackScrollerMeasuringPass;
- /**
- * Non-null if there's a heads-up notification that we're currently tracking the position of.
- */
+ /** Non-null if a heads-up notification's position is being tracked. */
@Nullable
private ExpandableNotificationRow mTrackedHeadsUpNotification;
private final ArrayList<Consumer<ExpandableNotificationRow>>
@@ -579,8 +524,9 @@
private final CommandQueue mCommandQueue;
private final UserManager mUserManager;
private final MediaDataManager mMediaDataManager;
+ @PanelState
+ private int mCurrentPanelState = STATE_CLOSED;
private final SysUiState mSysUiState;
-
private final NotificationShadeDepthController mDepthController;
private final NavigationBarController mNavigationBarController;
private final int mDisplayId;
@@ -590,6 +536,7 @@
private boolean mHeadsUpPinnedMode;
private boolean mAllowExpandForSmallExpansion;
private Runnable mExpandAfterLayoutRunnable;
+ private Runnable mHideExpandedRunnable;
/**
* The padding between the start of notifications and the qs boundary on the lockscreen.
@@ -597,94 +544,51 @@
* qs boundary to be padded.
*/
private int mLockscreenNotificationQSPadding;
-
/**
* The amount of progress we are currently in if we're transitioning to the full shade.
* 0.0f means we're not transitioning yet, while 1 means we're all the way in the full
* shade. This value can also go beyond 1.1 when we're overshooting!
*/
private float mTransitioningToFullShadeProgress;
-
/**
* Position of the qs bottom during the full shade transition. This is needed as the toppadding
* can change during state changes, which makes it much harder to do animations
*/
private int mTransitionToFullShadeQSPosition;
-
- /**
- * Distance that the full shade transition takes in order for qs to fully transition to the
- * shade.
- */
+ /** Distance a full shade transition takes in order for qs to fully transition to the shade. */
private int mDistanceForQSFullShadeTransition;
-
- /**
- * The translation amount for QS for the full shade transition
- */
+ /** The translation amount for QS for the full shade transition. */
private float mQsTranslationForFullShadeTransition;
- /**
- * The maximum overshoot allowed for the top padding for the full shade transition
- */
+ /** The maximum overshoot allowed for the top padding for the full shade transition. */
private int mMaxOverscrollAmountForPulse;
-
- /**
- * Should we animate the next bounds update
- */
+ /** Should we animate the next bounds update. */
private boolean mAnimateNextNotificationBounds;
- /**
- * The delay for the next bounds animation
- */
+ /** The delay for the next bounds animation. */
private long mNotificationBoundsAnimationDelay;
-
- /**
- * The duration of the notification bounds animation
- */
+ /** The duration of the notification bounds animation. */
private long mNotificationBoundsAnimationDuration;
- /**
- * Is this a collapse that started on the panel where we should allow the panel to intercept
- */
+ /** Whether a collapse that started on the panel should allow the panel to intercept. */
private boolean mIsPanelCollapseOnQQS;
-
private boolean mAnimatingQS;
-
- /**
- * The end bounds of a clipping animation.
- */
+ /** The end bounds of a clipping animation. */
private final Rect mQsClippingAnimationEndBounds = new Rect();
-
- /**
- * The animator for the qs clipping bounds.
- */
+ /** The animator for the qs clipping bounds. */
private ValueAnimator mQsClippingAnimation = null;
-
- /**
- * Is the current animator resetting the qs translation.
- */
+ /** Whether the current animator is resetting the qs translation. */
private boolean mIsQsTranslationResetAnimator;
- /**
- * Is the current animator resetting the pulse expansion after a drag down
- */
+ /** Whether the current animator is resetting the pulse expansion after a drag down. */
private boolean mIsPulseExpansionResetAnimator;
private final Rect mKeyguardStatusAreaClipBounds = new Rect();
private final Region mQsInterceptRegion = new Region();
-
- /**
- * The alpha of the views which only show on the keyguard but not in shade / shade locked
- */
+ /** Alpha of the views which only show on the keyguard but not in shade / shade locked. */
private float mKeyguardOnlyContentAlpha = 1.0f;
-
- /**
- * The translationY of the views which only show on the keyguard but in shade / shade locked.
- */
+ /** Y translation of the views that only show on the keyguard but in shade / shade locked. */
private int mKeyguardOnlyTransitionTranslationY = 0;
-
private float mUdfpsMaxYBurnInOffset;
-
- /**
- * Are we currently in gesture navigation
- */
+ /** Are we currently in gesture navigation. */
private boolean mIsGestureNavigation;
private int mOldLayoutDirection;
private NotificationShelfController mNotificationShelfController;
@@ -697,6 +601,7 @@
private int mQsClipTop;
private int mQsClipBottom;
private boolean mQsVisible;
+
private final ContentResolver mContentResolver;
private float mMinFraction;
@@ -715,55 +620,7 @@
private final NotificationListContainer mNotificationListContainer;
private final NotificationStackSizeCalculator mNotificationStackSizeCalculator;
-
private final NPVCDownEventState.Buffer mLastDownEvents;
-
- private final Runnable mAnimateKeyguardBottomAreaInvisibleEndRunnable =
- () -> mKeyguardBottomArea.setVisibility(View.GONE);
-
- private final AccessibilityDelegate mAccessibilityDelegate = new AccessibilityDelegate() {
- @Override
- public void onInitializeAccessibilityNodeInfo(View host,
- AccessibilityNodeInfo info) {
- super.onInitializeAccessibilityNodeInfo(host, info);
- info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_FORWARD);
- info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_UP);
- }
-
- @Override
- public boolean performAccessibilityAction(View host, int action, Bundle args) {
- if (action
- == AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_FORWARD.getId()
- || action
- == AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_UP.getId()) {
- mStatusBarKeyguardViewManager.showBouncer(true);
- return true;
- }
- return super.performAccessibilityAction(host, action, args);
- }
- };
-
- private final FalsingTapListener mFalsingTapListener = new FalsingTapListener() {
- @Override
- public void onAdditionalTapRequired() {
- if (mStatusBarStateController.getState() == StatusBarState.SHADE_LOCKED) {
- mTapAgainViewController.show();
- } else {
- mKeyguardIndicationController.showTransientIndication(
- R.string.notification_tap_again);
- }
-
- if (!mStatusBarStateController.isDozing()) {
- mVibratorHelper.vibrate(
- Process.myUid(),
- mView.getContext().getPackageName(),
- ADDITIONAL_TAP_REQUIRED_VIBRATION_EFFECT,
- "falsing-additional-tap-required",
- TOUCH_VIBRATION_ATTRIBUTES);
- }
- }
- };
-
private final CameraGestureHelper mCameraGestureHelper;
private final KeyguardBottomAreaViewModel mKeyguardBottomAreaViewModel;
private final KeyguardBottomAreaInteractor mKeyguardBottomAreaInteractor;
@@ -813,8 +670,20 @@
private boolean mGestureWaitForTouchSlop;
private boolean mIgnoreXTouchSlop;
private boolean mExpandLatencyTracking;
+
private final Runnable mFlingCollapseRunnable = () -> fling(0, false /* expand */,
mNextCollapseSpeedUpFactor, false /* expandBecauseOfFalsing */);
+ private final Runnable mAnimateKeyguardBottomAreaInvisibleEndRunnable =
+ () -> mKeyguardBottomArea.setVisibility(View.GONE);
+ private final Runnable mHeadsUpExistenceChangedRunnable = () -> {
+ setHeadsUpAnimatingAway(false);
+ updatePanelExpansionAndVisibility();
+ };
+ private final Runnable mMaybeHideExpandedRunnable = () -> {
+ if (getExpansionFraction() == 0.0f) {
+ getView().post(mHideExpandedRunnable);
+ }
+ };
@Inject
public NotificationPanelViewController(NotificationPanelView view,
@@ -849,7 +718,6 @@
KeyguardUserSwitcherComponent.Factory keyguardUserSwitcherComponentFactory,
KeyguardStatusBarViewComponent.Factory keyguardStatusBarViewComponentFactory,
LockscreenShadeTransitionController lockscreenShadeTransitionController,
- NotificationIconAreaController notificationIconAreaController,
AuthController authController,
ScrimController scrimController,
UserManager userManager,
@@ -858,7 +726,6 @@
AmbientState ambientState,
LockIconViewController lockIconViewController,
KeyguardMediaController keyguardMediaController,
- PrivacyDotViewController privacyDotViewController,
TapAgainViewController tapAgainViewController,
NavigationModeController navigationModeController,
NavigationBarController navigationBarController,
@@ -896,7 +763,6 @@
mLockscreenGestureLogger = lockscreenGestureLogger;
mShadeExpansionStateManager = shadeExpansionStateManager;
mShadeLog = shadeLogger;
- TouchHandler touchHandler = createTouchHandler();
mView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
@Override
public void onViewAttachedToWindow(View v) {
@@ -904,13 +770,12 @@
}
@Override
- public void onViewDetachedFromWindow(View v) {
- }
+ public void onViewDetachedFromWindow(View v) {}
});
- mView.addOnLayoutChangeListener(createLayoutChangeListener());
- mView.setOnTouchListener(touchHandler);
- mView.setOnConfigurationChangedListener(createOnConfigurationChangedListener());
+ mView.addOnLayoutChangeListener(new ShadeLayoutChangeListener());
+ mView.setOnTouchListener(createTouchHandler());
+ mView.setOnConfigurationChangedListener(config -> loadDimens());
mResources = mView.getResources();
mKeyguardStateController = keyguardStateController;
@@ -946,7 +811,6 @@
mInteractionJankMonitor = interactionJankMonitor;
mSystemClock = systemClock;
mKeyguardMediaController = keyguardMediaController;
- mPrivacyDotViewController = privacyDotViewController;
mMetricsLogger = metricsLogger;
mConfigurationController = configurationController;
mFlingAnimationUtilsBuilder = flingAnimationUtilsBuilder;
@@ -958,7 +822,6 @@
mKeyguardBottomAreaViewControllerProvider = keyguardBottomAreaViewControllerProvider;
mNotificationsQSContainerController.init();
mNotificationStackScrollLayoutController = notificationStackScrollLayoutController;
- mNotificationIconAreaController = notificationIconAreaController;
mKeyguardStatusViewComponentFactory = keyguardStatusViewComponentFactory;
mKeyguardStatusBarViewComponentFactory = keyguardStatusBarViewComponentFactory;
mDepthController = notificationShadeDepthController;
@@ -1001,10 +864,7 @@
mShadeTransitionController = shadeTransitionController;
lockscreenShadeTransitionController.setNotificationPanelController(this);
shadeTransitionController.setNotificationPanelViewController(this);
- DynamicPrivacyControlListener
- dynamicPrivacyControlListener =
- new DynamicPrivacyControlListener();
- dynamicPrivacyController.addListener(dynamicPrivacyControlListener);
+ dynamicPrivacyController.addListener(this::onDynamicPrivacyChanged);
shadeExpansionStateManager.addStateListener(this::onPanelStateChanged);
@@ -1028,13 +888,14 @@
mIsGestureNavigation = QuickStepContract.isGesturalMode(currentMode);
mView.setBackgroundColor(Color.TRANSPARENT);
- OnAttachStateChangeListener onAttachStateChangeListener = new OnAttachStateChangeListener();
+ ShadeAttachStateChangeListener
+ onAttachStateChangeListener = new ShadeAttachStateChangeListener();
mView.addOnAttachStateChangeListener(onAttachStateChangeListener);
if (mView.isAttachedToWindow()) {
onAttachStateChangeListener.onViewAttachedToWindow(mView);
}
- mView.setOnApplyWindowInsetsListener(new OnApplyWindowInsetsListener());
+ mView.setOnApplyWindowInsetsListener((v, insets) -> onApplyShadeWindowInsets(insets));
if (DEBUG_DRAWABLE) {
mView.getOverlay().add(new DebugDrawable());
@@ -1053,57 +914,68 @@
new KeyguardUnlockAnimationController.KeyguardUnlockAnimationListener() {
@Override
public void onUnlockAnimationFinished() {
- // Make sure the clock is in the correct position after the unlock animation
- // so that it's not in the wrong place when we show the keyguard again.
- positionClockAndNotifications(true /* forceClockUpdate */);
+ unlockAnimationFinished();
}
@Override
public void onUnlockAnimationStarted(
boolean playingCannedAnimation,
boolean isWakeAndUnlock,
- long unlockAnimationStartDelay,
+ long startDelay,
long unlockAnimationDuration) {
- // Disable blurs while we're unlocking so that panel expansion does not
- // cause blurring. This will eventually be re-enabled by the panel view on
- // ACTION_UP, since the user's finger might still be down after a swipe to
- // unlock gesture, and we don't want that to cause blurring either.
- mDepthController.setBlursDisabledForUnlock(mTracking);
-
- if (playingCannedAnimation && !isWakeAndUnlock) {
- // Hide the panel so it's not in the way or the surface behind the
- // keyguard, which will be appearing. If we're wake and unlocking, the
- // lock screen is hidden instantly so should not be flung away.
- if (isTracking() || isFlinging()) {
- // Instant collpase the notification panel since the notification
- // panel is already in the middle animating
- onTrackingStopped(false);
- instantCollapse();
- } else {
- mView.animate()
- .alpha(0f)
- .setStartDelay(0)
- // Translate up by 4%.
- .translationY(mView.getHeight() * -0.04f)
- // This start delay is to give us time to animate out before
- // the launcher icons animation starts, so use that as our
- // duration.
- .setDuration(unlockAnimationStartDelay)
- .setInterpolator(EMPHASIZED_ACCELERATE)
- .withEndAction(() -> {
- instantCollapse();
- mView.setAlpha(1f);
- mView.setTranslationY(0f);
- })
- .start();
- }
- }
+ unlockAnimationStarted(playingCannedAnimation, isWakeAndUnlock, startDelay);
}
});
mCameraGestureHelper = cameraGestureHelper;
mKeyguardBottomAreaInteractor = keyguardBottomAreaInteractor;
}
+ private void unlockAnimationFinished() {
+ // Make sure the clock is in the correct position after the unlock animation
+ // so that it's not in the wrong place when we show the keyguard again.
+ positionClockAndNotifications(true /* forceClockUpdate */);
+ }
+
+ private void unlockAnimationStarted(
+ boolean playingCannedAnimation,
+ boolean isWakeAndUnlock,
+ long unlockAnimationStartDelay) {
+ // Disable blurs while we're unlocking so that panel expansion does not
+ // cause blurring. This will eventually be re-enabled by the panel view on
+ // ACTION_UP, since the user's finger might still be down after a swipe to
+ // unlock gesture, and we don't want that to cause blurring either.
+ mDepthController.setBlursDisabledForUnlock(mTracking);
+
+ if (playingCannedAnimation && !isWakeAndUnlock) {
+ // Hide the panel so it's not in the way or the surface behind the
+ // keyguard, which will be appearing. If we're wake and unlocking, the
+ // lock screen is hidden instantly so should not be flung away.
+ if (isTracking() || mIsFlinging) {
+ // Instant collapse the notification panel since the notification
+ // panel is already in the middle animating
+ onTrackingStopped(false);
+ instantCollapse();
+ } else {
+ mView.animate()
+ .alpha(0f)
+ .setStartDelay(0)
+ // Translate up by 4%.
+ .translationY(mView.getHeight() * -0.04f)
+ // This start delay is to give us time to animate out before
+ // the launcher icons animation starts, so use that as our
+ // duration.
+ .setDuration(unlockAnimationStartDelay)
+ .setInterpolator(EMPHASIZED_ACCELERATE)
+ .withEndAction(() -> {
+ instantCollapse();
+ mView.setAlpha(1f);
+ mView.setTranslationY(0f);
+ })
+ .start();
+ }
+ }
+ }
+
@VisibleForTesting
void onFinishInflate() {
loadDimens();
@@ -1140,7 +1012,7 @@
R.id.notification_stack_scroller);
mNotificationStackScrollLayoutController.attach(stackScrollLayout);
mNotificationStackScrollLayoutController.setOnHeightChangedListener(
- mOnHeightChangedListener);
+ new NsslHeightChangedListener());
mNotificationStackScrollLayoutController.setOverscrollTopChangedListener(
mOnOverscrollTopChangedListener);
mNotificationStackScrollLayoutController.setOnScrollListener(this::onNotificationScrolled);
@@ -1261,11 +1133,6 @@
}
}
- private void setCentralSurfaces(CentralSurfaces centralSurfaces) {
- // TODO: this can be injected.
- mCentralSurfaces = centralSurfaces;
- }
-
public void updateResources() {
mSplitShadeNotificationsScrimMarginBottom =
mResources.getDimensionPixelSize(
@@ -1351,7 +1218,7 @@
@VisibleForTesting
void reInflateViews() {
- if (DEBUG_LOGCAT) Log.d(TAG, "reInflateViews");
+ debugLog("reInflateViews");
// Re-inflate the status view group.
KeyguardStatusView keyguardStatusView =
mNotificationContainerParent.findViewById(R.id.keyguard_status_view);
@@ -1430,6 +1297,11 @@
mNotificationPanelUnfoldAnimationController.ifPresent(u -> u.setup(mView));
}
+ @VisibleForTesting
+ void setQs(QS qs) {
+ mQs = qs;
+ }
+
private void attachSplitShadeMediaPlayerContainer(FrameLayout container) {
mKeyguardMediaController.attachSplitShadeContainer(container);
}
@@ -1444,12 +1316,7 @@
}
@VisibleForTesting
- boolean getClosing() {
- return mClosing;
- }
-
- @VisibleForTesting
- boolean getIsFlinging() {
+ boolean isFlinging() {
return mIsFlinging;
}
@@ -1924,13 +1791,13 @@
setQsExpandImmediate(true);
setShowShelfOnly(true);
}
- if (DEBUG) this.logf("collapse: " + this);
+ debugLog("collapse: %s", this);
if (canPanelBeCollapsed()) {
cancelHeightAnimator();
notifyExpandingStarted();
// Set after notifyExpandingStarted, as notifyExpandingStarted resets the closing state.
- setIsClosing(true);
+ setClosing(true);
if (delayed) {
mNextCollapseSpeedUpFactor = speedUpFactor;
this.mView.postDelayed(mFlingCollapseRunnable, 120);
@@ -1940,13 +1807,19 @@
}
}
- private void setQsExpandImmediate(boolean expandImmediate) {
+ @VisibleForTesting
+ void setQsExpandImmediate(boolean expandImmediate) {
if (expandImmediate != mQsExpandImmediate) {
mQsExpandImmediate = expandImmediate;
mShadeExpansionStateManager.notifyExpandImmediateChange(expandImmediate);
}
}
+ @VisibleForTesting
+ boolean isQsExpandImmediate() {
+ return mQsExpandImmediate;
+ }
+
private void setShowShelfOnly(boolean shelfOnly) {
mNotificationStackScrollLayoutController.setShouldShowShelfOnly(
shelfOnly && !mSplitShadeEnabled);
@@ -1954,7 +1827,7 @@
public void closeQs() {
cancelQsAnimation();
- setQsExpansion(mQsMinExpansionHeight);
+ setQsExpansionHeight(mQsMinExpansionHeight);
}
@VisibleForTesting
@@ -1992,7 +1865,7 @@
}
float height = mQsExpansionHeight;
mQsExpansionAnimator.cancel();
- setQsExpansion(height);
+ setQsExpansionHeight(height);
}
flingSettings(0 /* vel */, animateAway ? FLING_HIDE : FLING_COLLAPSE);
}
@@ -2016,7 +1889,7 @@
// case but currently motion in portrait looks worse than when using flingSettings.
// TODO: make below function transitioning smoothly also in portrait with null target
mLockscreenShadeTransitionController.goToLockedShade(
- /* expandedView= */null, /* needsQSAnimation= */false);
+ /* expandedView= */null, /* needsQSAnimation= */true);
} else if (isFullyCollapsed()) {
expand(true /* animate */);
} else {
@@ -2033,12 +1906,12 @@
}
}
- public void fling(float vel, boolean expand) {
+ private void fling(float vel) {
GestureRecorder gr = mCentralSurfaces.getGestureRecorder();
if (gr != null) {
gr.tag("fling " + ((vel > 0) ? "open" : "closed"), "notifications,v=" + vel);
}
- fling(vel, expand, 1.0f /* collapseSpeedUpFactor */, false);
+ fling(vel, true, 1.0f /* collapseSpeedUpFactor */, false);
}
@VisibleForTesting
@@ -2125,7 +1998,7 @@
@Override
public void onAnimationEnd(Animator animation) {
if (shouldSpringBack && !mCancelled) {
- // After the shade is flinged open to an overscrolled state, spring back
+ // After the shade is flung open to an overscrolled state, spring back
// the shade by reducing section padding to 0.
springBack();
} else {
@@ -2155,7 +2028,7 @@
}
private boolean onQsIntercept(MotionEvent event) {
- if (DEBUG_LOGCAT) Log.d(TAG, "onQsIntercept");
+ debugLog("onQsIntercept");
int pointerIndex = event.findPointerIndex(mQsTrackingPointer);
if (pointerIndex < 0) {
pointerIndex = 0;
@@ -2205,7 +2078,7 @@
// Already tracking because onOverscrolled was called. We need to update here
// so we don't stop for a frame until the next touch event gets handled in
// onTouchEvent.
- setQsExpansion(h + mInitialHeightOnTouch);
+ setQsExpansionHeight(h + mInitialHeightOnTouch);
trackMovement(event);
return true;
} else {
@@ -2216,7 +2089,7 @@
if ((h > touchSlop || (h < -touchSlop && mQsExpanded))
&& Math.abs(h) > Math.abs(x - mInitialTouchX)
&& shouldQuickSettingsIntercept(mInitialTouchX, mInitialTouchY, h)) {
- if (DEBUG_LOGCAT) Log.d(TAG, "onQsIntercept - start tracking expansion");
+ debugLog("onQsIntercept - start tracking expansion");
mView.getParent().requestDisallowInterceptTouchEvent(true);
mShadeLog.onQsInterceptMoveQsTrackingEnabled(h);
mQsTracking = true;
@@ -2275,7 +2148,7 @@
private void initDownStates(MotionEvent event) {
if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
mQsTouchAboveFalsingThreshold = mQsFullyExpanded;
- mDozingOnDown = isDozing();
+ mDozingOnDown = mDozing;
mDownX = event.getX();
mDownY = event.getY();
mCollapsedOnDown = isFullyCollapsed();
@@ -2325,7 +2198,7 @@
float vel = getCurrentQSVelocity();
boolean expandsQs = flingExpandsQs(vel);
if (expandsQs) {
- if (mFalsingManager.isUnlockingDisabled() || isFalseTouch(QUICK_SETTINGS)) {
+ if (mFalsingManager.isUnlockingDisabled() || isFalseTouch()) {
expandsQs = false;
} else {
logQsSwipeDown(y);
@@ -2364,9 +2237,9 @@
}
}
- private boolean isFalseTouch(@Classifier.InteractionType int interactionType) {
+ private boolean isFalseTouch() {
if (mFalsingManager.isClassifierEnabled()) {
- return mFalsingManager.isFalseTouch(interactionType);
+ return mFalsingManager.isFalseTouch(Classifier.QUICK_SETTINGS);
}
return !mQsTouchAboveFalsingThreshold;
}
@@ -2492,7 +2365,7 @@
private void handleQsDown(MotionEvent event) {
if (event.getActionMasked() == MotionEvent.ACTION_DOWN && shouldQuickSettingsIntercept(
event.getX(), event.getY(), -1)) {
- if (DEBUG_LOGCAT) Log.d(TAG, "handleQsDown");
+ debugLog("handleQsDown");
mFalsingCollector.onQsDown();
mShadeLog.logMotionEvent(event, "handleQsDown: down action, QS tracking enabled");
mQsTracking = true;
@@ -2506,9 +2379,7 @@
}
}
- /**
- * Input focus transfer is about to happen.
- */
+ /** Input focus transfer is about to happen. */
public void startWaitingForOpenPanelGesture() {
if (!isFullyCollapsed()) {
return;
@@ -2540,7 +2411,7 @@
} else {
// Window never will receive touch events that typically trigger haptic on open.
maybeVibrateOnOpening(false /* openingWithTouch */);
- fling(velocity > 1f ? 1000f * velocity : 0, true /* expand */);
+ fling(velocity > 1f ? 1000f * velocity : 0 /* expand */);
}
onTrackingStopped(false);
}
@@ -2614,9 +2485,9 @@
break;
case MotionEvent.ACTION_MOVE:
- if (DEBUG_LOGCAT) Log.d(TAG, "onQSTouch move");
+ debugLog("onQSTouch move");
mShadeLog.logMotionEvent(event, "onQsTouch: move action, setting QS expansion");
- setQsExpansion(h + mInitialHeightOnTouch);
+ setQsExpansionHeight(h + mInitialHeightOnTouch);
if (h >= getFalsingThreshold()) {
mQsTouchAboveFalsingThreshold = true;
}
@@ -2663,7 +2534,7 @@
// Reset scroll position and apply that position to the expanded height.
float height = mQsExpansionHeight;
- setQsExpansion(height);
+ setQsExpansionHeight(height);
updateExpandedHeightToMaxHeight();
mNotificationStackScrollLayoutController.checkSnoozeLeavebehind();
@@ -2691,6 +2562,9 @@
navigationBarView.onStatusBarPanelStateChanged();
}
mShadeExpansionStateManager.onQsExpansionChanged(expanded);
+ mShadeLog.logQsExpansionChanged("QS Expansion Changed.", expanded,
+ mQsMinExpansionHeight, mQsMaxExpansionHeight, mStackScrollerOverscrolling,
+ mDozing, mQsAnimatorExpand, mAnimatingQS);
}
}
@@ -2735,7 +2609,7 @@
mQs.setExpanded(mQsExpanded);
}
- void setQsExpansion(float height) {
+ void setQsExpansionHeight(float height) {
height = Math.min(Math.max(height, mQsMinExpansionHeight), mQsMaxExpansionHeight);
mQsFullyExpanded = height == mQsMaxExpansionHeight && mQsMaxExpansionHeight != 0;
boolean qsAnimatingAway = !mQsAnimatorExpand && mAnimatingQS;
@@ -2902,7 +2776,7 @@
}
private int calculateLeftQsClippingBound() {
- if (isFullWidth()) {
+ if (mIsFullWidth) {
// left bounds can ignore insets, it should always reach the edge of the screen
return 0;
} else {
@@ -2911,7 +2785,7 @@
}
private int calculateRightQsClippingBound() {
- if (isFullWidth()) {
+ if (mIsFullWidth) {
return getView().getRight() + mDisplayRightInset;
} else {
return mNotificationStackScrollLayoutController.getRight();
@@ -2979,7 +2853,7 @@
// Fancy clipping for quick settings
int radius = mScrimCornerRadius;
boolean clipStatusView = false;
- if (isFullWidth()) {
+ if (mIsFullWidth) {
// The padding on this area is large enough that we can use a cheaper clipping strategy
mKeyguardStatusAreaClipBounds.set(left, top, right, bottom);
clipStatusView = qsVisible;
@@ -3042,11 +2916,23 @@
// relative to NotificationStackScrollLayout
int nsslLeft = left - mNotificationStackScrollLayoutController.getLeft();
int nsslRight = right - mNotificationStackScrollLayoutController.getLeft();
- int nsslTop = top - mNotificationStackScrollLayoutController.getTop();
+ int nsslTop = getNotificationsClippingTopBounds(top);
int nsslBottom = bottom - mNotificationStackScrollLayoutController.getTop();
int bottomRadius = mSplitShadeEnabled ? radius : 0;
+ int topRadius = mSplitShadeEnabled && mExpandingFromHeadsUp ? 0 : radius;
mNotificationStackScrollLayoutController.setRoundedClippingBounds(
- nsslLeft, nsslTop, nsslRight, nsslBottom, radius, bottomRadius);
+ nsslLeft, nsslTop, nsslRight, nsslBottom, topRadius, bottomRadius);
+ }
+
+ private int getNotificationsClippingTopBounds(int qsTop) {
+ if (mSplitShadeEnabled && mExpandingFromHeadsUp) {
+ // in split shade nssl has extra top margin so clipping at top 0 is not enough, we need
+ // to set top clipping bound to negative value to allow HUN to go up to the top edge of
+ // the screen without clipping.
+ return -mAmbientState.getStackTopMargin();
+ } else {
+ return qsTop - mNotificationStackScrollLayoutController.getTop();
+ }
}
private float getQSEdgePosition() {
@@ -3117,10 +3003,7 @@
}
}
- /**
- * @return the topPadding of notifications when on keyguard not respecting quick settings
- * expansion
- */
+ /** Returns the topPadding of notifications when on keyguard not respecting QS expansion. */
private int getKeyguardNotificationStaticPadding() {
if (!mKeyguardShowing) {
return 0;
@@ -3152,17 +3035,18 @@
* shade. 0.0f means we're not transitioning yet.
*/
public void setTransitionToFullShadeAmount(float pxAmount, boolean animate, long delay) {
- if (animate && isFullWidth()) {
+ if (animate && mIsFullWidth) {
animateNextNotificationBounds(StackStateAnimator.ANIMATION_DURATION_GO_TO_FULL_SHADE,
delay);
mIsQsTranslationResetAnimator = mQsTranslationForFullShadeTransition > 0.0f;
}
-
- if (mSplitShadeEnabled) {
- updateQsExpansionForLockscreenToShadeTransition(pxAmount);
- }
float endPosition = 0;
if (pxAmount > 0.0f) {
+ if (mSplitShadeEnabled) {
+ float qsHeight = MathUtils.lerp(mQsMinExpansionHeight, mQsMaxExpansionHeight,
+ mLockscreenShadeTransitionController.getQSDragProgress());
+ setQsExpansionHeight(qsHeight);
+ }
if (mNotificationStackScrollLayoutController.getVisibleNotificationCount() == 0
&& !mMediaDataManager.hasActiveMediaOrRecommendation()) {
// No notifications are visible, let's animate to the height of qs instead
@@ -3200,22 +3084,7 @@
updateQsExpansion();
}
- private void updateQsExpansionForLockscreenToShadeTransition(float pxAmount) {
- float qsExpansion = 0;
- if (pxAmount > 0.0f) {
- qsExpansion = MathUtils.lerp(mQsMinExpansionHeight, mQsMaxExpansionHeight,
- mLockscreenShadeTransitionController.getQSDragProgress());
- }
- // SHADE_LOCKED means transition is over and we don't want further updates
- if (mBarState != SHADE_LOCKED) {
- setQsExpansion(qsExpansion);
- }
- }
-
- /**
- * Notify the panel that the pulse expansion has finished and that we're going to the full
- * shade
- */
+ /** Called when pulse expansion has finished and this is going to the full shade. */
public void onPulseExpansionFinished() {
animateNextNotificationBounds(StackStateAnimator.ANIMATION_DURATION_GO_TO_FULL_SHADE, 0);
mIsPulseExpansionResetAnimator = true;
@@ -3270,9 +3139,7 @@
}
}
- /**
- * @see #flingSettings(float, int, Runnable, boolean)
- */
+ /** @see #flingSettings(float, int, Runnable, boolean) */
public void flingSettings(float vel, int type) {
flingSettings(vel, type, null /* onFinishRunnable */, false /* isClick */);
}
@@ -3329,7 +3196,7 @@
animator.setDuration(350);
}
animator.addUpdateListener(
- animation -> setQsExpansion((Float) animation.getAnimatedValue()));
+ animation -> setQsExpansionHeight((Float) animation.getAnimatedValue()));
animator.addListener(new AnimatorListenerAdapter() {
private boolean mIsCanceled;
@@ -3405,7 +3272,8 @@
return !mSplitShadeEnabled && (isInSettings() || mIsPanelCollapseOnQQS);
}
- public int getMaxPanelHeight() {
+ @VisibleForTesting
+ int getMaxPanelHeight() {
int min = mStatusBarMinHeight;
if (!(mBarState == KEYGUARD)
&& mNotificationStackScrollLayoutController.getNotGoneChildCount() == 0) {
@@ -3439,19 +3307,35 @@
}
private void onHeightUpdated(float expandedHeight) {
+ if (expandedHeight <= 0) {
+ mShadeLog.logExpansionChanged("onHeightUpdated: fully collapsed.",
+ mExpandedFraction, isExpanded(), mTracking, mExpansionDragDownAmountPx);
+ } else if (isFullyExpanded()) {
+ mShadeLog.logExpansionChanged("onHeightUpdated: fully expanded.",
+ mExpandedFraction, isExpanded(), mTracking, mExpansionDragDownAmountPx);
+ }
if (!mQsExpanded || mQsExpandImmediate || mIsExpanding && mQsExpandedWhenExpandingStarted) {
// Updating the clock position will set the top padding which might
// trigger a new panel height and re-position the clock.
// This is a circular dependency and should be avoided, otherwise we'll have
// a stack overflow.
if (mStackScrollerMeasuringPass > 2) {
- if (DEBUG_LOGCAT) Log.d(TAG, "Unstable notification panel height. Aborting.");
+ debugLog("Unstable notification panel height. Aborting.");
} else {
positionClockAndNotifications();
}
}
- if (mQsExpandImmediate || (mQsExpanded && !mQsTracking && mQsExpansionAnimator == null
- && !mQsExpansionFromOverscroll)) {
+ // Below is true when QS are expanded and we swipe up from the same bottom of panel to
+ // close the whole shade with one motion. Also this will be always true when closing
+ // split shade as there QS are always expanded so every collapsing motion is motion from
+ // expanded QS to closed panel
+ boolean collapsingShadeFromExpandedQs = mQsExpanded && !mQsTracking
+ && mQsExpansionAnimator == null && !mQsExpansionFromOverscroll;
+ boolean goingBetweenClosedShadeAndExpandedQs =
+ mQsExpandImmediate || collapsingShadeFromExpandedQs;
+ // we don't want to update QS expansion when HUN is visible because then the whole shade is
+ // initially hidden, even though it has non-zero height
+ if (goingBetweenClosedShadeAndExpandedQs && !mHeadsUpManager.isTrackingHeadsUp()) {
float qsExpansionFraction;
if (mSplitShadeEnabled) {
qsExpansionFraction = 1;
@@ -3470,7 +3354,7 @@
}
float targetHeight = mQsMinExpansionHeight
+ qsExpansionFraction * (mQsMaxExpansionHeight - mQsMinExpansionHeight);
- setQsExpansion(targetHeight);
+ setQsExpansionHeight(targetHeight);
}
updateExpandedHeight(expandedHeight);
updateHeader();
@@ -3572,9 +3456,7 @@
return alpha;
}
- /**
- * Hides the header when notifications are colliding with it.
- */
+ /** Hides the header when notifications are colliding with it. */
private void updateHeader() {
if (mBarState == KEYGUARD) {
mKeyguardStatusBarViewController.updateViewState();
@@ -3717,7 +3599,7 @@
if (mAnimateAfterExpanding) {
notifyExpandingStarted();
beginJankMonitoring();
- fling(0, true /* expand */);
+ fling(0 /* expand */);
} else {
setExpandedFraction(1f);
}
@@ -3754,6 +3636,24 @@
}
+ private void falsingAdditionalTapRequired() {
+ if (mStatusBarStateController.getState() == StatusBarState.SHADE_LOCKED) {
+ mTapAgainViewController.show();
+ } else {
+ mKeyguardIndicationController.showTransientIndication(
+ R.string.notification_tap_again);
+ }
+
+ if (!mStatusBarStateController.isDozing()) {
+ mVibratorHelper.vibrate(
+ Process.myUid(),
+ mView.getContext().getPackageName(),
+ ADDITIONAL_TAP_REQUIRED_VIBRATION_EFFECT,
+ "falsing-additional-tap-required",
+ TOUCH_VIBRATION_ATTRIBUTES);
+ }
+ }
+
private void onTrackingStarted() {
mFalsingCollector.onTrackingStarted(!mKeyguardStateController.canDismissLockScreen());
endClosing();
@@ -3788,7 +3688,7 @@
private void updateMaxHeadsUpTranslation() {
mNotificationStackScrollLayoutController.setHeadsUpBoundaries(
- getHeight(), mNavigationBarBottomHeight);
+ mView.getHeight(), mNavigationBarBottomHeight);
}
@VisibleForTesting
@@ -3833,7 +3733,8 @@
|| !isTracking());
}
- public int getMaxPanelTransitionDistance() {
+ @VisibleForTesting
+ int getMaxPanelTransitionDistance() {
// Traditionally the value is based on the number of notifications. On split-shade, we want
// the required distance to be a specific and constant value, to make sure the expansion
// motion has the expected speed. We also only want this on non-lockscreen for now.
@@ -3889,10 +3790,9 @@
}
@VisibleForTesting
- void setIsClosing(boolean isClosing) {
- boolean wasClosing = isClosing();
- mClosing = isClosing;
- if (wasClosing != isClosing) {
+ void setClosing(boolean isClosing) {
+ if (mClosing != isClosing) {
+ mClosing = isClosing;
mShadeExpansionStateManager.notifyPanelCollapsingChanged(isClosing);
}
mAmbientState.setIsClosing(isClosing);
@@ -3905,10 +3805,6 @@
}
}
- public boolean isDozing() {
- return mDozing;
- }
-
public void setQsScrimEnabled(boolean qsScrimEnabled) {
boolean changed = mQsScrimEnabled != qsScrimEnabled;
mQsScrimEnabled = qsScrimEnabled;
@@ -3921,7 +3817,7 @@
mKeyguardStatusViewController.dozeTimeTick();
}
- private boolean onMiddleClicked() {
+ private void onMiddleClicked() {
switch (mBarState) {
case KEYGUARD:
if (!mDozingOnDown) {
@@ -3943,14 +3839,12 @@
startUnlockHintAnimation();
}
}
- return true;
+ break;
case StatusBarState.SHADE_LOCKED:
if (!mQsExpanded) {
mStatusBarStateController.setState(KEYGUARD);
}
- return true;
- default:
- return true;
+ break;
}
}
@@ -4024,17 +3918,9 @@
updateStatusBarIcons();
}
- /**
- * @return whether the notifications are displayed full width and don't have any margins on
- * the side.
- */
- public boolean isFullWidth() {
- return mIsFullWidth;
- }
-
private void updateStatusBarIcons() {
boolean showIconsWhenExpanded =
- (isPanelVisibleBecauseOfHeadsUp() || isFullWidth())
+ (isPanelVisibleBecauseOfHeadsUp() || mIsFullWidth)
&& getExpandedHeight() < getOpeningHeight();
if (showIconsWhenExpanded && isOnKeyguard()) {
showIconsWhenExpanded = false;
@@ -4049,10 +3935,7 @@
return mBarState == KEYGUARD;
}
- /**
- * Called when heads-up notification is being dragged up or down to indicate what's the starting
- * height for shade motion
- */
+ /** Called when a HUN is dragged up or down to indicate the starting height for shade motion. */
public void setHeadsUpDraggingStartingHeight(int startHeight) {
mHeadsUpStartHeight = startHeight;
float scrimMinFraction;
@@ -4106,25 +3989,18 @@
setLaunchingAffordance(false);
}
- /**
- * Set whether we are currently launching an affordance. This is currently only set when
- * launched via a camera gesture.
- */
+ /** Set whether we are currently launching an affordance (i.e. camera gesture). */
private void setLaunchingAffordance(boolean launchingAffordance) {
mLaunchingAffordance = launchingAffordance;
mKeyguardBypassController.setLaunchingAffordance(launchingAffordance);
}
- /**
- * Return true when a bottom affordance is launching an occluded activity with a splash screen.
- */
+ /** Returns whether a bottom affordance is launching an occluded activity with splash screen. */
public boolean isLaunchingAffordanceWithPreview() {
return mLaunchingAffordance;
}
- /**
- * Whether the camera application can be launched for the camera launch gesture.
- */
+ /** Whether the camera application can be launched by the camera launch gesture. */
public boolean canCameraGestureBeLaunched() {
return mCameraGestureHelper.canCameraGestureBeLaunched(mBarState);
}
@@ -4137,22 +4013,19 @@
&& mHeadsUpAppearanceController.shouldBeVisible()) {
return false;
}
- return !isFullWidth() || !mShowIconsWhenExpanded;
+ return !mIsFullWidth || !mShowIconsWhenExpanded;
}
- public final QS.ScrollListener mScrollListener = new QS.ScrollListener() {
- @Override
- public void onQsPanelScrollChanged(int scrollY) {
- mLargeScreenShadeHeaderController.setQsScrollY(scrollY);
- if (scrollY > 0 && !mQsFullyExpanded) {
- if (DEBUG_LOGCAT) Log.d(TAG, "Scrolling while not expanded. Forcing expand");
- // If we are scrolling QS, we should be fully expanded.
- expandWithQs();
- }
+ private void onQsPanelScrollChanged(int scrollY) {
+ mLargeScreenShadeHeaderController.setQsScrollY(scrollY);
+ if (scrollY > 0 && !mQsFullyExpanded) {
+ debugLog("Scrolling while not expanded. Forcing expand");
+ // If we are scrolling QS, we should be fully expanded.
+ expandWithQs();
}
- };
+ }
- private final FragmentListener mFragmentListener = new FragmentListener() {
+ private final class QsFragmentListener implements FragmentListener {
@Override
public void onFragmentViewCreated(String tag, Fragment fragment) {
mQs = (QS) fragment;
@@ -4169,7 +4042,7 @@
final int height = bottom - top;
final int oldHeight = oldBottom - oldTop;
if (height != oldHeight) {
- mHeightListener.onQsHeightChanged();
+ onQsHeightChanged();
}
});
mQs.setCollapsedMediaVisibilityChangedListener((visible) -> {
@@ -4182,7 +4055,7 @@
mLockscreenShadeTransitionController.setQS(mQs);
mShadeTransitionController.setQs(mQs);
mNotificationStackScrollLayoutController.setQsHeader((ViewGroup) mQs.getHeader());
- mQs.setScrollListener(mScrollListener);
+ mQs.setScrollListener(mQsScrollListener);
updateQsExpansion();
}
@@ -4195,7 +4068,7 @@
mQs = null;
}
}
- };
+ }
private void animateNextNotificationBounds(long duration, long delay) {
mAnimateNextNotificationBounds = true;
@@ -4285,13 +4158,7 @@
mKeyguardStatusViewController.setStatusAccessibilityImportance(mode);
}
- /**
- * TODO: this should be removed.
- * It's not correct to pass this view forward because other classes will end up adding
- * children to it. Theme will be out of sync.
- *
- * @return bottom area view
- */
+ //TODO(b/254875405): this should be removed.
public KeyguardBottomAreaView getKeyguardBottomAreaView() {
return mKeyguardBottomArea;
}
@@ -4320,11 +4187,8 @@
mHeadsUpAppearanceController = headsUpAppearanceController;
}
- /**
- * Starts the animation before we dismiss Keyguard, i.e. an disappearing animation on the
- * security view of the bouncer.
- */
- public void onBouncerPreHideAnimation() {
+ /** Called before animating Keyguard dismissal, i.e. the animation dismissing the bouncer. */
+ public void startBouncerPreHideAnimation() {
if (mKeyguardQsUserSwitchController != null) {
mKeyguardQsUserSwitchController.setKeyguardQsUserSwitchVisibility(
mBarState,
@@ -4341,9 +4205,7 @@
}
}
- /**
- * Updates the views to the initial state for the fold to AOD animation
- */
+ /** Updates the views to the initial state for the fold to AOD animation. */
public void prepareFoldToAodAnimation() {
// Force show AOD UI even if we are not locked
showAodUi();
@@ -4385,14 +4247,11 @@
public void onAnimationEnd(Animator animation) {
endAction.run();
}
- }).setUpdateListener(anim -> {
- mKeyguardStatusViewController.animateFoldToAod(anim.getAnimatedFraction());
- }).start();
+ }).setUpdateListener(anim -> mKeyguardStatusViewController.animateFoldToAod(
+ anim.getAnimatedFraction())).start();
}
- /**
- * Cancels fold to AOD transition and resets view state
- */
+ /** Cancels fold to AOD transition and resets view state. */
public void cancelFoldToAodAnimation() {
cancelAnimation();
resetAlpha();
@@ -4436,42 +4295,11 @@
}
}
- public boolean hasActiveClearableNotifications() {
- return mNotificationStackScrollLayoutController.hasActiveClearableNotifications(ROWS_ALL);
- }
public RemoteInputController.Delegate createRemoteInputDelegate() {
return mNotificationStackScrollLayoutController.createDelegate();
}
- /**
- * Updates the notification views' sections and status bar icons. This is
- * triggered by the NotificationPresenter whenever there are changes to the underlying
- * notification data being displayed. In the new notification pipeline, this is handled in
- * {@link ShadeViewManager}.
- */
- public void updateNotificationViews() {
- mNotificationStackScrollLayoutController.updateFooter();
-
- mNotificationIconAreaController.updateNotificationIcons(createVisibleEntriesList());
- }
-
- private List<ListEntry> createVisibleEntriesList() {
- List<ListEntry> entries = new ArrayList<>(
- mNotificationStackScrollLayoutController.getChildCount());
- for (int i = 0; i < mNotificationStackScrollLayoutController.getChildCount(); i++) {
- View view = mNotificationStackScrollLayoutController.getChildAt(i);
- if (view instanceof ExpandableNotificationRow) {
- entries.add(((ExpandableNotificationRow) view).getEntry());
- }
- }
- return entries;
- }
-
- public void onUpdateRowStates() {
- mNotificationStackScrollLayoutController.onUpdateRowStates();
- }
-
public boolean hasPulsingNotifications() {
return mNotificationListContainer.hasPulsingNotifications();
}
@@ -4488,16 +4316,6 @@
mNotificationStackScrollLayoutController.runAfterAnimationFinished(r);
}
- private Runnable mHideExpandedRunnable;
- private final Runnable mMaybeHideExpandedRunnable = new Runnable() {
- @Override
- public void run() {
- if (getExpansionFraction() == 0.0f) {
- mView.post(mHideExpandedRunnable);
- }
- }
- };
-
/**
* Initialize objects instead of injecting to avoid circular dependencies.
*
@@ -4507,7 +4325,9 @@
CentralSurfaces centralSurfaces,
Runnable hideExpandedRunnable,
NotificationShelfController notificationShelfController) {
- setCentralSurfaces(centralSurfaces);
+ // TODO(b/254859580): this can be injected.
+ mCentralSurfaces = centralSurfaces;
+
mHideExpandedRunnable = hideExpandedRunnable;
mNotificationStackScrollLayoutController.setShelfController(notificationShelfController);
mNotificationShelfController = notificationShelfController;
@@ -4515,10 +4335,6 @@
updateMaxDisplayedNotifications(true);
}
- public void setAlpha(float alpha) {
- mView.setAlpha(alpha);
- }
-
public void resetTranslation() {
mView.setTranslationX(0f);
}
@@ -4537,22 +4353,18 @@
ViewGroupFadeHelper.reset(mView);
}
- public void addOnGlobalLayoutListener(ViewTreeObserver.OnGlobalLayoutListener listener) {
+ void addOnGlobalLayoutListener(ViewTreeObserver.OnGlobalLayoutListener listener) {
mView.getViewTreeObserver().addOnGlobalLayoutListener(listener);
}
- public void removeOnGlobalLayoutListener(ViewTreeObserver.OnGlobalLayoutListener listener) {
+ void removeOnGlobalLayoutListener(ViewTreeObserver.OnGlobalLayoutListener listener) {
mView.getViewTreeObserver().removeOnGlobalLayoutListener(listener);
}
- public MyOnHeadsUpChangedListener getOnHeadsUpChangedListener() {
+ public ShadeHeadsUpChangedListener getOnHeadsUpChangedListener() {
return mOnHeadsUpChangedListener;
}
- public int getHeight() {
- return mView.getHeight();
- }
-
public void setHeaderDebugInfo(String text) {
if (DEBUG_DRAWABLE) mHeaderDebugInfo = text;
}
@@ -4561,10 +4373,6 @@
mConfigurationListener.onThemeChanged();
}
- private OnLayoutChangeListener createLayoutChangeListener() {
- return new OnLayoutChangeListener();
- }
-
@VisibleForTesting
TouchHandler createTouchHandler() {
return new TouchHandler();
@@ -4619,10 +4427,6 @@
}
};
- private OnConfigurationChangedListener createOnConfigurationChangedListener() {
- return new OnConfigurationChangedListener();
- }
-
public NotificationStackScrollLayoutController getNotificationStackScrollLayoutController() {
return mNotificationStackScrollLayoutController;
}
@@ -4663,13 +4467,7 @@
);
}
- private void unregisterSettingsChangeListener() {
- mContentResolver.unregisterContentObserver(mSettingsChangeObserver);
- }
-
- /**
- * Updates notification panel-specific flags on {@link SysUiState}.
- */
+ /** Updates notification panel-specific flags on {@link SysUiState}. */
public void updateSystemUiStateFlags() {
if (SysUiState.DEBUG) {
Log.d(TAG, "Updating panel sysui state flags: fullyExpanded="
@@ -4681,8 +4479,10 @@
.commitUpdate(mDisplayId);
}
- private void logf(String fmt, Object... args) {
- Log.v(TAG, (mViewName != null ? (mViewName + ": ") : "") + String.format(fmt, args));
+ private void debugLog(String fmt, Object... args) {
+ if (DEBUG_LOGCAT) {
+ Log.d(TAG, (mViewName != null ? (mViewName + ": ") : "") + String.format(fmt, args));
+ }
}
@VisibleForTesting
@@ -4729,8 +4529,6 @@
private void startOpening(MotionEvent event) {
updatePanelExpansionAndVisibility();
- // Reset at start so haptic can be triggered as soon as panel starts to open.
- mHasVibratedOnOpen = false;
//TODO: keyguard opens QS a different way; log that too?
// Log the position of the swipe that opened the panel
@@ -4748,9 +4546,8 @@
* Maybe vibrate as panel is opened.
*
* @param openingWithTouch Whether the panel is being opened with touch. If the panel is
- * instead
- * being opened programmatically (such as by the open panel gesture), we
- * always play haptic.
+ * instead being opened programmatically (such as by the open panel
+ * gesture), we always play haptic.
*/
private void maybeVibrateOnOpening(boolean openingWithTouch) {
if (mVibrateOnOpening) {
@@ -4849,8 +4646,8 @@
} else if (!mCentralSurfaces.isBouncerShowing()
&& !mStatusBarKeyguardViewManager.isShowingAlternateAuthOrAnimating()
&& !mKeyguardStateController.isKeyguardGoingAway()) {
- boolean expands = onEmptySpaceClick();
- onTrackingStopped(expands);
+ onEmptySpaceClick();
+ onTrackingStopped(true);
}
mVelocityTracker.clear();
}
@@ -4862,7 +4659,7 @@
private void endClosing() {
if (mClosing) {
- setIsClosing(false);
+ setClosing(false);
onClosingFinished();
}
}
@@ -4897,7 +4694,7 @@
boolean expandBecauseOfFalsing) {
float target = expand ? getMaxPanelHeight() : 0;
if (!expand) {
- setIsClosing(true);
+ setClosing(true);
}
flingToHeight(vel, expand, target, collapseSpeedUpFactor, expandBecauseOfFalsing);
}
@@ -4932,13 +4729,9 @@
animator.start();
}
- public String getName() {
- return mViewName;
- }
-
@VisibleForTesting
void setExpandedHeight(float height) {
- if (DEBUG) logf("setExpandedHeight(%.1f)", height);
+ debugLog("setExpandedHeight(%.1f)", height);
setExpandedHeightInternal(height);
}
@@ -5030,12 +4823,12 @@
return mExpandedHeight;
}
- public float getExpandedFraction() {
+ private float getExpandedFraction() {
return mExpandedFraction;
}
public boolean isFullyExpanded() {
- return mExpandedHeight >= getMaxPanelHeight();
+ return mExpandedHeight >= getMaxPanelTransitionDistance();
}
public boolean isFullyCollapsed() {
@@ -5046,10 +4839,6 @@
return mClosing || mIsLaunchAnimationRunning;
}
- public boolean isFlinging() {
- return mIsFlinging;
- }
-
public boolean isTracking() {
return mTracking;
}
@@ -5196,8 +4985,7 @@
*/
public void updatePanelExpansionAndVisibility() {
mShadeExpansionStateManager.onPanelExpansionChanged(
- mExpandedFraction, isExpanded(),
- mTracking, mExpansionDragDownAmountPx);
+ mExpandedFraction, isExpanded(), mTracking, mExpansionDragDownAmountPx);
updateVisibility();
}
@@ -5210,16 +4998,11 @@
&& !mIsSpringBackAnimation;
}
- /**
- * Gets called when the user performs a click anywhere in the empty area of the panel.
- *
- * @return whether the panel will be expanded after the action performed by this method
- */
- private boolean onEmptySpaceClick() {
- if (mHintAnimationRunning) {
- return true;
+ /** Called when the user performs a click anywhere in the empty area of the panel. */
+ private void onEmptySpaceClick() {
+ if (!mHintAnimationRunning) {
+ onMiddleClicked();
}
- return onMiddleClicked();
}
@VisibleForTesting
@@ -5236,7 +5019,7 @@
/** Returns the NotificationPanelView. */
public ViewGroup getView() {
- // TODO: remove this method, or at least reduce references to it.
+ // TODO(b/254878364): remove this method, or at least reduce references to it.
return mView;
}
@@ -5276,12 +5059,11 @@
return mShadeExpansionStateManager;
}
- private class OnHeightChangedListener implements ExpandableView.OnHeightChangedListener {
+ private final class NsslHeightChangedListener implements
+ ExpandableView.OnHeightChangedListener {
@Override
public void onHeightChanged(ExpandableView view, boolean needsAnimation) {
-
- // Block update if we are in quick settings and just the top padding changed
- // (i.e. view == null).
+ // Block update if we are in QS and just the top padding changed (i.e. view == null).
if (view == null && mQsExpanded) {
return;
}
@@ -5305,26 +5087,22 @@
}
@Override
- public void onReset(ExpandableView view) {
+ public void onReset(ExpandableView view) {}
+ }
+
+ private void collapseOrExpand() {
+ onQsExpansionStarted();
+ if (mQsExpanded) {
+ flingSettings(0 /* vel */, FLING_COLLAPSE, null /* onFinishRunnable */,
+ true /* isClick */);
+ } else if (isQsExpansionEnabled()) {
+ mLockscreenGestureLogger.write(MetricsEvent.ACTION_SHADE_QS_TAP, 0, 0);
+ flingSettings(0 /* vel */, FLING_EXPAND, null /* onFinishRunnable */,
+ true /* isClick */);
}
}
- private class CollapseExpandAction implements Runnable {
- @Override
- public void run() {
- onQsExpansionStarted();
- if (mQsExpanded) {
- flingSettings(0 /* vel */, FLING_COLLAPSE, null /* onFinishRunnable */,
- true /* isClick */);
- } else if (isQsExpansionEnabled()) {
- mLockscreenGestureLogger.write(MetricsEvent.ACTION_SHADE_QS_TAP, 0, 0);
- flingSettings(0 /* vel */, FLING_EXPAND, null /* onFinishRunnable */,
- true /* isClick */);
- }
- }
- }
-
- private class OnOverscrollTopChangedListener implements
+ private final class NsslOverscrollTopChangedListener implements
NotificationStackScrollLayout.OnOverscrollTopChangedListener {
@Override
public void onOverscrollTopChanged(float amount, boolean isRubberbanded) {
@@ -5341,7 +5119,7 @@
mQsExpansionFromOverscroll = rounded != 0f;
mLastOverscroll = rounded;
updateQsState();
- setQsExpansion(mQsMinExpansionHeight + rounded);
+ setQsExpansionHeight(mQsMinExpansionHeight + rounded);
}
@Override
@@ -5358,7 +5136,7 @@
// make sure we can expand
setOverScrolling(false);
}
- setQsExpansion(mQsExpansionHeight);
+ setQsExpansionHeight(mQsExpansionHeight);
boolean canExpand = isQsExpansionEnabled();
flingSettings(!canExpand && open ? 0f : velocity,
open && canExpand ? FLING_EXPAND : FLING_COLLAPSE, () -> {
@@ -5368,27 +5146,16 @@
}
}
- private class DynamicPrivacyControlListener implements DynamicPrivacyController.Listener {
- @Override
- public void onDynamicPrivacyChanged() {
- // Do not request animation when pulsing or waking up, otherwise the clock wiill be out
- // of sync with the notification panel.
- if (mLinearDarkAmount != 0) {
- return;
- }
- mAnimateNextPositionUpdate = true;
+ private void onDynamicPrivacyChanged() {
+ // Do not request animation when pulsing or waking up, otherwise the clock will be out
+ // of sync with the notification panel.
+ if (mLinearDarkAmount != 0) {
+ return;
}
+ mAnimateNextPositionUpdate = true;
}
- private class OnEmptySpaceClickListener implements
- NotificationStackScrollLayout.OnEmptySpaceClickListener {
- @Override
- public void onEmptySpaceClicked(float x, float y) {
- onEmptySpaceClick();
- }
- }
-
- private class MyOnHeadsUpChangedListener implements OnHeadsUpChangedListener {
+ private final class ShadeHeadsUpChangedListener implements OnHeadsUpChangedListener {
@Override
public void onHeadsUpPinnedModeChanged(final boolean inPinnedMode) {
if (inPinnedMode) {
@@ -5428,32 +5195,31 @@
}
}
- private class HeightListener implements QS.HeightListener {
- public void onQsHeightChanged() {
- mQsMaxExpansionHeight = mQs != null ? mQs.getDesiredHeight() : 0;
- if (mQsExpanded && mQsFullyExpanded) {
- mQsExpansionHeight = mQsMaxExpansionHeight;
- requestScrollerTopPaddingUpdate(false /* animate */);
- updateExpandedHeightToMaxHeight();
- }
- if (mAccessibilityManager.isEnabled()) {
- mView.setAccessibilityPaneTitle(determineAccessibilityPaneTitle());
- }
- mNotificationStackScrollLayoutController.setMaxTopPadding(mQsMaxExpansionHeight);
+ private void onQsHeightChanged() {
+ mQsMaxExpansionHeight = mQs != null ? mQs.getDesiredHeight() : 0;
+ if (mQsExpanded && mQsFullyExpanded) {
+ mQsExpansionHeight = mQsMaxExpansionHeight;
+ requestScrollerTopPaddingUpdate(false /* animate */);
+ updateExpandedHeightToMaxHeight();
}
+ if (mAccessibilityManager.isEnabled()) {
+ mView.setAccessibilityPaneTitle(determineAccessibilityPaneTitle());
+ }
+ mNotificationStackScrollLayoutController.setMaxTopPadding(mQsMaxExpansionHeight);
}
- private class ConfigurationListener implements ConfigurationController.ConfigurationListener {
+ private final class ConfigurationListener implements
+ ConfigurationController.ConfigurationListener {
@Override
public void onThemeChanged() {
- if (DEBUG_LOGCAT) Log.d(TAG, "onThemeChanged");
+ debugLog("onThemeChanged");
reInflateViews();
}
@Override
public void onSmallestScreenWidthChanged() {
Trace.beginSection("onSmallestScreenWidthChanged");
- if (DEBUG_LOGCAT) Log.d(TAG, "onSmallestScreenWidthChanged");
+ debugLog("onSmallestScreenWidthChanged");
// Can affect multi-user switcher visibility as it depends on screen size by default:
// it is enabled only for devices with large screens (see config_keyguardUserSwitcher)
@@ -5470,27 +5236,26 @@
@Override
public void onDensityOrFontScaleChanged() {
- if (DEBUG_LOGCAT) Log.d(TAG, "onDensityOrFontScaleChanged");
+ debugLog("onDensityOrFontScaleChanged");
reInflateViews();
}
}
- private class SettingsChangeObserver extends ContentObserver {
-
+ private final class SettingsChangeObserver extends ContentObserver {
SettingsChangeObserver(Handler handler) {
super(handler);
}
@Override
public void onChange(boolean selfChange) {
- if (DEBUG_LOGCAT) Log.d(TAG, "onSettingsChanged");
+ debugLog("onSettingsChanged");
// Can affect multi-user switcher visibility
reInflateViews();
}
}
- private class StatusBarStateListener implements StateListener {
+ private final class StatusBarStateListener implements StateListener {
@Override
public void onStateChanged(int statusBarState) {
boolean goingToFullShade = mStatusBarStateController.goingToFullShade();
@@ -5551,7 +5316,7 @@
}
} else {
// this else branch means we are doing one of:
- // - from KEYGUARD and SHADE (but not expanded shade)
+ // - from KEYGUARD to SHADE (but not fully expanded as when swiping from the top)
// - from SHADE to KEYGUARD
// - from SHADE_LOCKED to SHADE
// - getting notified again about the current SHADE or KEYGUARD state
@@ -5646,21 +5411,19 @@
setExpandedFraction(1f);
}
- /**
- * Sets the overstretch amount in raw pixels when dragging down.
- */
- public void setOverStrechAmount(float amount) {
+ /** Sets the overstretch amount in raw pixels when dragging down. */
+ public void setOverStretchAmount(float amount) {
float progress = amount / mView.getHeight();
- float overstretch = Interpolators.getOvershootInterpolation(progress);
- mOverStretchAmount = overstretch * mMaxOverscrollAmountForPulse;
+ float overStretch = Interpolators.getOvershootInterpolation(progress);
+ mOverStretchAmount = overStretch * mMaxOverscrollAmountForPulse;
positionClockAndNotifications(true /* forceUpdate */);
}
- private class OnAttachStateChangeListener implements View.OnAttachStateChangeListener {
+ private final class ShadeAttachStateChangeListener implements View.OnAttachStateChangeListener {
@Override
public void onViewAttachedToWindow(View v) {
mFragmentService.getFragmentHostManager(mView)
- .addTagListener(QS.TAG, mFragmentListener);
+ .addTagListener(QS.TAG, mQsFragmentListener);
mStatusBarStateController.addCallback(mStatusBarStateListener);
mStatusBarStateListener.onStateChanged(mStatusBarStateController.getState());
mConfigurationController.addCallback(mConfigurationListener);
@@ -5675,16 +5438,16 @@
@Override
public void onViewDetachedFromWindow(View v) {
- unregisterSettingsChangeListener();
+ mContentResolver.unregisterContentObserver(mSettingsChangeObserver);
mFragmentService.getFragmentHostManager(mView)
- .removeTagListener(QS.TAG, mFragmentListener);
+ .removeTagListener(QS.TAG, mQsFragmentListener);
mStatusBarStateController.removeCallback(mStatusBarStateListener);
mConfigurationController.removeCallback(mConfigurationListener);
mFalsingManager.removeTapListener(mFalsingTapListener);
}
}
- private final class OnLayoutChangeListener implements View.OnLayoutChangeListener {
+ private final class ShadeLayoutChangeListener implements View.OnLayoutChangeListener {
@Override
public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft,
int oldTop, int oldRight, int oldBottom) {
@@ -5693,7 +5456,7 @@
mHasLayoutedSinceDown = true;
if (mUpdateFlingOnLayout) {
abortAnimations();
- fling(mUpdateFlingVelocity, true /* expands */);
+ fling(mUpdateFlingVelocity);
mUpdateFlingOnLayout = false;
}
updateMaxDisplayedNotifications(!shouldAvoidChangingNotificationsCount());
@@ -5720,21 +5483,18 @@
startQsSizeChangeAnimation(oldMaxHeight, mQsMaxExpansionHeight);
}
} else if (!mQsExpanded && mQsExpansionAnimator == null) {
- setQsExpansion(mQsMinExpansionHeight + mLastOverscroll);
+ setQsExpansionHeight(mQsMinExpansionHeight + mLastOverscroll);
} else {
mShadeLog.v("onLayoutChange: qs expansion not set");
}
updateExpandedHeight(getExpandedHeight());
updateHeader();
- // If we are running a size change animation, the animation takes care of the height of
- // the container. However, if we are not animating, we always need to make the QS
- // container
- // the desired height so when closing the QS detail, it stays smaller after the size
- // change
- // animation is finished but the detail view is still being animated away (this
- // animation
- // takes longer than the size change animation).
+ // If we are running a size change animation, the animation takes care of the height
+ // of the container. However, if we are not animating, we always need to make the QS
+ // container the desired height so when closing the QS detail, it stays smaller after
+ // the size change animation is finished but the detail view is still being animated
+ // away (this animation takes longer than the size change animation).
if (mQsSizeChangeAnimator == null && mQs != null) {
mQs.setHeightOverride(mQs.getDesiredHeight());
}
@@ -5760,13 +5520,12 @@
}
}
- private class DebugDrawable extends Drawable {
-
+ private final class DebugDrawable extends Drawable {
private final Set<Integer> mDebugTextUsedYPositions = new HashSet<>();
private final Paint mDebugPaint = new Paint();
@Override
- public void draw(@androidx.annotation.NonNull @NonNull Canvas canvas) {
+ public void draw(@NonNull Canvas canvas) {
mDebugTextUsedYPositions.clear();
mDebugPaint.setColor(Color.RED);
@@ -5844,18 +5603,17 @@
}
}
- private class OnApplyWindowInsetsListener implements View.OnApplyWindowInsetsListener {
- public WindowInsets onApplyWindowInsets(View v, WindowInsets insets) {
- // the same types of insets that are handled in NotificationShadeWindowView
- int insetTypes = WindowInsets.Type.systemBars() | WindowInsets.Type.displayCutout();
- Insets combinedInsets = insets.getInsetsIgnoringVisibility(insetTypes);
- mDisplayTopInset = combinedInsets.top;
- mDisplayRightInset = combinedInsets.right;
+ @NonNull
+ private WindowInsets onApplyShadeWindowInsets(WindowInsets insets) {
+ // the same types of insets that are handled in NotificationShadeWindowView
+ int insetTypes = WindowInsets.Type.systemBars() | WindowInsets.Type.displayCutout();
+ Insets combinedInsets = insets.getInsetsIgnoringVisibility(insetTypes);
+ mDisplayTopInset = combinedInsets.top;
+ mDisplayRightInset = combinedInsets.right;
- mNavigationBarBottomHeight = insets.getStableInsetBottom();
- updateMaxHeadsUpTranslation();
- return insets;
- }
+ mNavigationBarBottomHeight = insets.getStableInsetBottom();
+ updateMaxHeadsUpTranslation();
+ return insets;
}
/** Removes any pending runnables that would collapse the panel. */
@@ -5863,9 +5621,6 @@
mView.removeCallbacks(mMaybeHideExpandedRunnable);
}
- @PanelState
- private int mCurrentPanelState = STATE_CLOSED;
-
private void onPanelStateChanged(@PanelState int state) {
updateQSExpansionEnabledAmbient();
@@ -5902,6 +5657,11 @@
}
@VisibleForTesting
+ StateListener getStatusBarStateListener() {
+ return mStatusBarStateListener;
+ }
+
+ @VisibleForTesting
boolean isHintAnimationRunning() {
return mHintAnimationRunning;
}
@@ -5949,7 +5709,7 @@
}
if (!isFullyCollapsed() && onQsIntercept(event)) {
- if (DEBUG_LOGCAT) Log.d(TAG, "onQsIntercept true");
+ debugLog("onQsIntercept true");
return true;
}
if (mInstantExpanding || !mNotificationsDragEnabled || mTouchDisabled || (mMotionAborted
@@ -6152,7 +5912,6 @@
*
* Flinging is also enabled in order to open or close the shade.
*/
-
int pointerIndex = event.findPointerIndex(mTrackingPointer);
if (pointerIndex < 0) {
pointerIndex = 0;
@@ -6168,6 +5927,7 @@
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
+ mShadeLog.logMotionEvent(event, "onTouch: down action");
startExpandMotion(x, y, false /* startTracking */, mExpandedHeight);
mMinExpandHeight = 0.0f;
mPanelClosedOnDown = isFullyCollapsed();
@@ -6214,6 +5974,10 @@
}
break;
case MotionEvent.ACTION_MOVE:
+ if (isFullyCollapsed()) {
+ // If panel is fully collapsed, reset haptic effect before adding movement.
+ mHasVibratedOnOpen = false;
+ }
addMovement(event);
if (!isFullyCollapsed()) {
maybeVibrateOnOpening(true /* openingWithTouch */);
@@ -6252,6 +6016,7 @@
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
+ mShadeLog.logMotionEvent(event, "onTouch: up/cancel action");
addMovement(event);
endMotionEvent(event, x, y, false /* forceCancel */);
// mHeightAnimator is null, there is no remaining frame, ends instrumenting.
@@ -6268,15 +6033,6 @@
}
}
- /** Listens for config changes. */
- public class OnConfigurationChangedListener implements
- NotificationPanelView.OnConfigurationChangedListener {
- @Override
- public void onConfigurationChanged(Configuration newConfig) {
- loadDimens();
- }
- }
-
static class SplitShadeTransitionAdapter extends Transition {
private static final String PROP_BOUNDS = "splitShadeTransitionAdapter:bounds";
private static final String[] TRANSITION_PROPERTIES = { PROP_BOUNDS };
@@ -6326,5 +6082,27 @@
return TRANSITION_PROPERTIES;
}
}
+
+ private final class ShadeAccessibilityDelegate extends AccessibilityDelegate {
+ @Override
+ public void onInitializeAccessibilityNodeInfo(View host,
+ AccessibilityNodeInfo info) {
+ super.onInitializeAccessibilityNodeInfo(host, info);
+ info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_FORWARD);
+ info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_UP);
+ }
+
+ @Override
+ public boolean performAccessibilityAction(View host, int action, Bundle args) {
+ if (action
+ == AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_FORWARD.getId()
+ || action
+ == AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_UP.getId()) {
+ mStatusBarKeyguardViewManager.showBouncer(true);
+ return true;
+ }
+ return super.performAccessibilityAction(host, action, args);
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeLogger.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeLogger.kt
index 2b788d8..7f1bba3 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeLogger.kt
@@ -77,4 +77,50 @@
}
)
}
+
+ fun logExpansionChanged(
+ message: String,
+ fraction: Float,
+ expanded: Boolean,
+ tracking: Boolean,
+ dragDownPxAmount: Float,
+ ) {
+ log(LogLevel.VERBOSE, {
+ str1 = message
+ double1 = fraction.toDouble()
+ bool1 = expanded
+ bool2 = tracking
+ long1 = dragDownPxAmount.toLong()
+ }, {
+ "$str1 fraction=$double1,expanded=$bool1," +
+ "tracking=$bool2," + "dragDownPxAmount=$dragDownPxAmount"
+ })
+ }
+
+ fun logQsExpansionChanged(
+ message: String,
+ qsExpanded: Boolean,
+ qsMinExpansionHeight: Int,
+ qsMaxExpansionHeight: Int,
+ stackScrollerOverscrolling: Boolean,
+ dozing: Boolean,
+ qsAnimatorExpand: Boolean,
+ animatingQs: Boolean
+ ) {
+ log(LogLevel.VERBOSE, {
+ str1 = message
+ bool1 = qsExpanded
+ int1 = qsMinExpansionHeight
+ int2 = qsMaxExpansionHeight
+ bool2 = stackScrollerOverscrolling
+ bool3 = dozing
+ bool4 = qsAnimatorExpand
+ // 0 = false, 1 = true
+ long1 = animatingQs.compareTo(false).toLong()
+ }, {
+ "$str1 qsExpanded=$bool1,qsMinExpansionHeight=$int1,qsMaxExpansionHeight=$int2," +
+ "stackScrollerOverscrolling=$bool2,dozing=$bool3,qsAnimatorExpand=$bool4," +
+ "animatingQs=$long1"
+ })
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
index a2e4536..b8302d7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
@@ -663,7 +663,7 @@
} else {
pulseHeight = height
val overflow = nsslController.setPulseHeight(height)
- notificationPanelController.setOverStrechAmount(overflow)
+ notificationPanelController.setOverStretchAmount(overflow)
val transitionHeight = if (keyguardBypassController.bypassEnabled) height else 0.0f
transitionToShadeAmountCommon(transitionHeight)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt
index fc984618..5873837 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt
@@ -48,7 +48,8 @@
import com.android.systemui.plugins.FalsingManager
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.settings.UserTracker
-import com.android.systemui.shared.regionsampling.RegionSamplingInstance
+import com.android.systemui.shared.regionsampling.RegionSampler
+import com.android.systemui.shared.regionsampling.UpdateColorCallback
import com.android.systemui.statusbar.phone.KeyguardBypassController
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.statusbar.policy.DeviceProvisionedController
@@ -90,8 +91,8 @@
// Smartspace can be used on multiple displays, such as when the user casts their screen
private var smartspaceViews = mutableSetOf<SmartspaceView>()
- private var regionSamplingInstances =
- mutableMapOf<SmartspaceView, RegionSamplingInstance>()
+ private var regionSamplers =
+ mutableMapOf<SmartspaceView, RegionSampler>()
private val regionSamplingEnabled =
featureFlags.isEnabled(Flags.REGION_SAMPLING)
@@ -101,27 +102,23 @@
private var showSensitiveContentForManagedUser = false
private var managedUserHandle: UserHandle? = null
- private val updateFun = object : RegionSamplingInstance.UpdateColorCallback {
- override fun updateColors() {
- updateTextColorFromRegionSampler()
- }
- }
+ private val updateFun: UpdateColorCallback = { updateTextColorFromRegionSampler() }
// TODO: Move logic into SmartspaceView
var stateChangeListener = object : View.OnAttachStateChangeListener {
override fun onViewAttachedToWindow(v: View) {
smartspaceViews.add(v as SmartspaceView)
- var regionSamplingInstance = RegionSamplingInstance(
+ var regionSampler = RegionSampler(
v,
uiExecutor,
bgExecutor,
regionSamplingEnabled,
updateFun
)
- initializeTextColors(regionSamplingInstance)
- regionSamplingInstance.startRegionSampler()
- regionSamplingInstances.put(v, regionSamplingInstance)
+ initializeTextColors(regionSampler)
+ regionSampler.startRegionSampler()
+ regionSamplers.put(v, regionSampler)
connectSession()
updateTextColorFromWallpaper()
@@ -131,9 +128,9 @@
override fun onViewDetachedFromWindow(v: View) {
smartspaceViews.remove(v as SmartspaceView)
- var regionSamplingInstance = regionSamplingInstances.getValue(v)
- regionSamplingInstance.stopRegionSampler()
- regionSamplingInstances.remove(v)
+ var regionSampler = regionSamplers.getValue(v)
+ regionSampler.stopRegionSampler()
+ regionSamplers.remove(v)
if (smartspaceViews.isEmpty()) {
disconnect()
@@ -363,19 +360,19 @@
}
}
- private fun initializeTextColors(regionSamplingInstance: RegionSamplingInstance) {
+ private fun initializeTextColors(regionSampler: RegionSampler) {
val lightThemeContext = ContextThemeWrapper(context, R.style.Theme_SystemUI_LightWallpaper)
val darkColor = Utils.getColorAttrDefaultColor(lightThemeContext, R.attr.wallpaperTextColor)
val darkThemeContext = ContextThemeWrapper(context, R.style.Theme_SystemUI)
val lightColor = Utils.getColorAttrDefaultColor(darkThemeContext, R.attr.wallpaperTextColor)
- regionSamplingInstance.setForegroundColors(lightColor, darkColor)
+ regionSampler.setForegroundColors(lightColor, darkColor)
}
private fun updateTextColorFromRegionSampler() {
smartspaceViews.forEach {
- val textColor = regionSamplingInstances.getValue(it).currentForegroundColor()
+ val textColor = regionSamplers.getValue(it).currentForegroundColor()
it.setPrimaryTextColor(textColor)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.kt
index 8a31ed9..470cbcb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.kt
@@ -198,6 +198,13 @@
// At this point we just need to initiate the transfer
val summaryUpdate = mPostedEntries[logicalSummary.key]
+ // Because we now know for certain that some child is going to alert for this summary
+ // (as we have found a child to transfer the alert to), mark the group as having
+ // interrupted. This will allow us to know in the future that the "should heads up"
+ // state of this group has already been handled, just not via the summary entry itself.
+ logicalSummary.setInterruption()
+ mLogger.logSummaryMarkedInterrupted(logicalSummary.key, childToReceiveParentAlert.key)
+
// If the summary was not attached, then remove the alert from the detached summary.
// Otherwise we can simply ignore its posted update.
if (!isSummaryAttached) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorLogger.kt
index dfaa291..473c35d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorLogger.kt
@@ -69,4 +69,13 @@
"updating entry via ranking applied: $str1 updated shouldHeadsUp=$bool1"
})
}
+
+ fun logSummaryMarkedInterrupted(summaryKey: String, childKey: String) {
+ buffer.log(TAG, LogLevel.DEBUG, {
+ str1 = summaryKey
+ str2 = childKey
+ }, {
+ "marked group summary as interrupted: $str1 for alert transfer to child: $str2"
+ })
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index df705c5..c4ef28e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -1383,7 +1383,7 @@
if (height < minExpansionHeight) {
mClipRect.left = 0;
mClipRect.right = getWidth();
- mClipRect.top = 0;
+ mClipRect.top = getNotificationsClippingTopBound();
mClipRect.bottom = (int) height;
height = minExpansionHeight;
setRequestedClipBounds(mClipRect);
@@ -1444,6 +1444,17 @@
notifyAppearChangedListeners();
}
+ private int getNotificationsClippingTopBound() {
+ if (isHeadsUpTransition()) {
+ // HUN in split shade can go higher than bottom of NSSL when swiping up so we want
+ // to give it extra clipping margin. Because clipping has rounded corners, we also
+ // need to account for that corner clipping.
+ return -mAmbientState.getStackTopMargin() - mCornerRadius;
+ } else {
+ return 0;
+ }
+ }
+
private void notifyAppearChangedListeners() {
float appear;
float expandAmount;
@@ -1482,7 +1493,6 @@
public void updateClipping() {
boolean clipped = mRequestedClipBounds != null && !mInHeadsUpPinnedMode
&& !mHeadsUpAnimatingAway;
- boolean clipToOutline = false;
if (mIsClipped != clipped) {
mIsClipped = clipped;
}
@@ -1498,7 +1508,7 @@
setClipBounds(null);
}
- setClipToOutline(clipToOutline);
+ setClipToOutline(false);
}
/**
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 d227ed3..eb7a742 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -3468,10 +3468,7 @@
mNavigationBarController.showPinningEscapeToast(mDisplayId);
}
- /**
- * TODO: Remove this method. Views should not be passed forward. Will cause theme issues.
- * @return bottom area view
- */
+ //TODO(b/254875405): this should be removed.
@Override
public KeyguardBottomAreaView getKeyguardBottomAreaView() {
return mNotificationPanelViewController.getKeyguardBottomAreaView();
@@ -4184,7 +4181,7 @@
*/
@Override
public void onBouncerPreHideAnimation() {
- mNotificationPanelViewController.onBouncerPreHideAnimation();
+ mNotificationPanelViewController.startBouncerPreHideAnimation();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/MobileConnectivityModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/MobileConnectivityModel.kt
new file mode 100644
index 0000000..e618905
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/MobileConnectivityModel.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.pipeline.mobile.data.model
+
+import android.net.NetworkCapabilities
+
+/** Provides information about a mobile network connection */
+data class MobileConnectivityModel(
+ /** Whether mobile is the connected transport see [NetworkCapabilities.TRANSPORT_CELLULAR] */
+ val isConnected: Boolean = false,
+ /** Whether the mobile transport is validated [NetworkCapabilities.NET_CAPABILITY_VALIDATED] */
+ val isValidated: Boolean = false,
+)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionRepository.kt
index 06e8f46..581842b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionRepository.kt
@@ -16,11 +16,15 @@
package com.android.systemui.statusbar.pipeline.mobile.data.repository
+import android.content.Context
+import android.database.ContentObserver
+import android.provider.Settings.Global
import android.telephony.CellSignalStrength
import android.telephony.CellSignalStrengthCdma
import android.telephony.ServiceState
import android.telephony.SignalStrength
import android.telephony.SubscriptionInfo
+import android.telephony.SubscriptionManager
import android.telephony.TelephonyCallback
import android.telephony.TelephonyDisplayInfo
import android.telephony.TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE
@@ -34,6 +38,7 @@
import com.android.systemui.statusbar.pipeline.mobile.data.model.toDataConnectionType
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.logOutputChange
+import com.android.systemui.util.settings.GlobalSettings
import java.lang.IllegalStateException
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
@@ -42,9 +47,12 @@
import kotlinx.coroutines.asExecutor
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
-import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.mapLatest
+import kotlinx.coroutines.flow.merge
+import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.stateIn
/**
@@ -65,14 +73,23 @@
*/
val subscriptionModelFlow: Flow<MobileSubscriptionModel>
/** Observable tracking [TelephonyManager.isDataConnectionAllowed] */
- val dataEnabled: Flow<Boolean>
+ val dataEnabled: StateFlow<Boolean>
+ /**
+ * True if this connection represents the default subscription per
+ * [SubscriptionManager.getDefaultDataSubscriptionId]
+ */
+ val isDefaultDataSubscription: StateFlow<Boolean>
}
@Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
@OptIn(ExperimentalCoroutinesApi::class)
class MobileConnectionRepositoryImpl(
+ private val context: Context,
private val subId: Int,
private val telephonyManager: TelephonyManager,
+ private val globalSettings: GlobalSettings,
+ defaultDataSubId: StateFlow<Int>,
+ globalMobileDataSettingChangedEvent: Flow<Unit>,
bgDispatcher: CoroutineDispatcher,
logger: ConnectivityPipelineLogger,
scope: CoroutineScope,
@@ -86,6 +103,8 @@
}
}
+ private val telephonyCallbackEvent = MutableSharedFlow<Unit>(extraBufferCapacity = 1)
+
override val subscriptionModelFlow: StateFlow<MobileSubscriptionModel> = run {
var state = MobileSubscriptionModel()
conflatedCallbackFlow {
@@ -165,33 +184,75 @@
telephonyManager.registerTelephonyCallback(bgDispatcher.asExecutor(), callback)
awaitClose { telephonyManager.unregisterTelephonyCallback(callback) }
}
+ .onEach { telephonyCallbackEvent.tryEmit(Unit) }
.logOutputChange(logger, "MobileSubscriptionModel")
.stateIn(scope, SharingStarted.WhileSubscribed(), state)
}
+ /** Produces whenever the mobile data setting changes for this subId */
+ private val localMobileDataSettingChangedEvent: Flow<Unit> = conflatedCallbackFlow {
+ val observer =
+ object : ContentObserver(null) {
+ override fun onChange(selfChange: Boolean) {
+ trySend(Unit)
+ }
+ }
+
+ globalSettings.registerContentObserver(
+ globalSettings.getUriFor("${Global.MOBILE_DATA}$subId"),
+ /* notifyForDescendants */ true,
+ observer
+ )
+
+ awaitClose { context.contentResolver.unregisterContentObserver(observer) }
+ }
+
/**
* There are a few cases where we will need to poll [TelephonyManager] so we can update some
* internal state where callbacks aren't provided. Any of those events should be merged into
* this flow, which can be used to trigger the polling.
*/
- private val telephonyPollingEvent: Flow<Unit> = subscriptionModelFlow.map {}
+ private val telephonyPollingEvent: Flow<Unit> =
+ merge(
+ telephonyCallbackEvent,
+ localMobileDataSettingChangedEvent,
+ globalMobileDataSettingChangedEvent,
+ )
- override val dataEnabled: Flow<Boolean> = telephonyPollingEvent.map { dataConnectionAllowed() }
+ override val dataEnabled: StateFlow<Boolean> =
+ telephonyPollingEvent
+ .mapLatest { dataConnectionAllowed() }
+ .stateIn(scope, SharingStarted.WhileSubscribed(), dataConnectionAllowed())
private fun dataConnectionAllowed(): Boolean = telephonyManager.isDataConnectionAllowed
+ override val isDefaultDataSubscription: StateFlow<Boolean> =
+ defaultDataSubId
+ .mapLatest { it == subId }
+ .stateIn(scope, SharingStarted.WhileSubscribed(), defaultDataSubId.value == subId)
+
class Factory
@Inject
constructor(
+ private val context: Context,
private val telephonyManager: TelephonyManager,
private val logger: ConnectivityPipelineLogger,
+ private val globalSettings: GlobalSettings,
@Background private val bgDispatcher: CoroutineDispatcher,
@Application private val scope: CoroutineScope,
) {
- fun build(subId: Int): MobileConnectionRepository {
+ fun build(
+ subId: Int,
+ defaultDataSubId: StateFlow<Int>,
+ globalMobileDataSettingChangedEvent: Flow<Unit>,
+ ): MobileConnectionRepository {
return MobileConnectionRepositoryImpl(
+ context,
subId,
telephonyManager.createForSubscriptionId(subId),
+ globalSettings,
+ defaultDataSubId,
+ globalMobileDataSettingChangedEvent,
bgDispatcher,
logger,
scope,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepository.kt
index 0e2428a..c3c1f14 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepository.kt
@@ -16,15 +16,27 @@
package com.android.systemui.statusbar.pipeline.mobile.data.repository
+import android.annotation.SuppressLint
import android.content.Context
import android.content.IntentFilter
+import android.database.ContentObserver
+import android.net.ConnectivityManager
+import android.net.ConnectivityManager.NetworkCallback
+import android.net.Network
+import android.net.NetworkCapabilities
+import android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED
+import android.net.NetworkCapabilities.TRANSPORT_CELLULAR
+import android.provider.Settings
+import android.provider.Settings.Global.MOBILE_DATA
import android.telephony.CarrierConfigManager
import android.telephony.SubscriptionInfo
import android.telephony.SubscriptionManager
+import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID
import android.telephony.TelephonyCallback
import android.telephony.TelephonyCallback.ActiveDataSubscriptionIdListener
import android.telephony.TelephonyManager
import androidx.annotation.VisibleForTesting
+import com.android.internal.telephony.PhoneConstants
import com.android.settingslib.mobile.MobileMappings
import com.android.settingslib.mobile.MobileMappings.Config
import com.android.systemui.broadcast.BroadcastDispatcher
@@ -32,7 +44,9 @@
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectivityModel
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
+import com.android.systemui.util.settings.GlobalSettings
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
@@ -40,10 +54,12 @@
import kotlinx.coroutines.asExecutor
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
-import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.mapLatest
+import kotlinx.coroutines.flow.merge
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.withContext
@@ -57,13 +73,22 @@
val subscriptionsFlow: Flow<List<SubscriptionInfo>>
/** Observable for the subscriptionId of the current mobile data connection */
- val activeMobileDataSubscriptionId: Flow<Int>
+ val activeMobileDataSubscriptionId: StateFlow<Int>
/** Observable for [MobileMappings.Config] tracking the defaults */
val defaultDataSubRatConfig: StateFlow<Config>
+ /** Tracks [SubscriptionManager.getDefaultDataSubscriptionId] */
+ val defaultDataSubId: StateFlow<Int>
+
+ /** The current connectivity status for the default mobile network connection */
+ val defaultMobileNetworkConnectivity: StateFlow<MobileConnectivityModel>
+
/** Get or create a repository for the line of service for the given subscription ID */
fun getRepoForSubId(subId: Int): MobileConnectionRepository
+
+ /** Observe changes to the [Settings.Global.MOBILE_DATA] setting */
+ val globalMobileDataSettingChangedEvent: Flow<Unit>
}
@Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
@@ -72,10 +97,12 @@
class MobileConnectionsRepositoryImpl
@Inject
constructor(
+ private val connectivityManager: ConnectivityManager,
private val subscriptionManager: SubscriptionManager,
private val telephonyManager: TelephonyManager,
private val logger: ConnectivityPipelineLogger,
broadcastDispatcher: BroadcastDispatcher,
+ private val globalSettings: GlobalSettings,
private val context: Context,
@Background private val bgDispatcher: CoroutineDispatcher,
@Application private val scope: CoroutineScope,
@@ -121,17 +148,26 @@
telephonyManager.registerTelephonyCallback(bgDispatcher.asExecutor(), callback)
awaitClose { telephonyManager.unregisterTelephonyCallback(callback) }
}
+ .stateIn(scope, started = SharingStarted.WhileSubscribed(), INVALID_SUBSCRIPTION_ID)
+
+ private val defaultDataSubIdChangeEvent: MutableSharedFlow<Unit> =
+ MutableSharedFlow(extraBufferCapacity = 1)
+
+ override val defaultDataSubId: StateFlow<Int> =
+ broadcastDispatcher
+ .broadcastFlow(
+ IntentFilter(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED)
+ ) { intent, _ ->
+ intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY, INVALID_SUBSCRIPTION_ID)
+ }
+ .distinctUntilChanged()
+ .onEach { defaultDataSubIdChangeEvent.tryEmit(Unit) }
.stateIn(
scope,
- started = SharingStarted.WhileSubscribed(),
- SubscriptionManager.INVALID_SUBSCRIPTION_ID
+ SharingStarted.WhileSubscribed(),
+ SubscriptionManager.getDefaultDataSubscriptionId()
)
- private val defaultDataSubChangedEvent =
- broadcastDispatcher.broadcastFlow(
- IntentFilter(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED)
- )
-
private val carrierConfigChangedEvent =
broadcastDispatcher.broadcastFlow(
IntentFilter(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED)
@@ -148,9 +184,8 @@
* This flow will produce whenever the default data subscription or the carrier config changes.
*/
override val defaultDataSubRatConfig: StateFlow<Config> =
- combine(defaultDataSubChangedEvent, carrierConfigChangedEvent) { _, _ ->
- Config.readConfig(context)
- }
+ merge(defaultDataSubIdChangeEvent, carrierConfigChangedEvent)
+ .mapLatest { Config.readConfig(context) }
.stateIn(
scope,
SharingStarted.WhileSubscribed(),
@@ -168,6 +203,57 @@
?: createRepositoryForSubId(subId).also { subIdRepositoryCache[subId] = it }
}
+ /**
+ * In single-SIM devices, the [MOBILE_DATA] setting is phone-wide. For multi-SIM, the individual
+ * connection repositories also observe the URI for [MOBILE_DATA] + subId.
+ */
+ override val globalMobileDataSettingChangedEvent: Flow<Unit> = conflatedCallbackFlow {
+ val observer =
+ object : ContentObserver(null) {
+ override fun onChange(selfChange: Boolean) {
+ trySend(Unit)
+ }
+ }
+
+ globalSettings.registerContentObserver(
+ globalSettings.getUriFor(MOBILE_DATA),
+ true,
+ observer
+ )
+
+ awaitClose { context.contentResolver.unregisterContentObserver(observer) }
+ }
+
+ @SuppressLint("MissingPermission")
+ override val defaultMobileNetworkConnectivity: StateFlow<MobileConnectivityModel> =
+ conflatedCallbackFlow {
+ val callback =
+ object : NetworkCallback(FLAG_INCLUDE_LOCATION_INFO) {
+ override fun onLost(network: Network) {
+ // Send a disconnected model when lost. Maybe should create a sealed
+ // type or null here?
+ trySend(MobileConnectivityModel())
+ }
+
+ override fun onCapabilitiesChanged(
+ network: Network,
+ caps: NetworkCapabilities
+ ) {
+ trySend(
+ MobileConnectivityModel(
+ isConnected = caps.hasTransport(TRANSPORT_CELLULAR),
+ isValidated = caps.hasCapability(NET_CAPABILITY_VALIDATED),
+ )
+ )
+ }
+ }
+
+ connectivityManager.registerDefaultNetworkCallback(callback)
+
+ awaitClose { connectivityManager.unregisterNetworkCallback(callback) }
+ }
+ .stateIn(scope, SharingStarted.WhileSubscribed(), MobileConnectivityModel())
+
private fun isValidSubId(subId: Int): Boolean {
subscriptionsFlow.value.forEach {
if (it.subscriptionId == subId) {
@@ -181,7 +267,11 @@
@VisibleForTesting fun getSubIdRepoCache() = subIdRepositoryCache
private fun createRepositoryForSubId(subId: Int): MobileConnectionRepository {
- return mobileConnectionRepositoryFactory.build(subId)
+ return mobileConnectionRepositoryFactory.build(
+ subId,
+ defaultDataSubId,
+ globalMobileDataSettingChangedEvent,
+ )
}
private fun dropUnusedReposFromCache(newInfos: List<SubscriptionInfo>) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/UserSetupRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/UserSetupRepository.kt
index 77de849..91886bb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/UserSetupRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/UserSetupRepository.kt
@@ -26,7 +26,6 @@
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.channels.awaitClose
-import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.mapLatest
@@ -40,7 +39,7 @@
*/
interface UserSetupRepository {
/** Observable tracking [DeviceProvisionedController.isUserSetup] */
- val isUserSetupFlow: Flow<Boolean>
+ val isUserSetupFlow: StateFlow<Boolean>
}
@Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt
index f99d278c..0da84f0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt
@@ -18,81 +18,109 @@
import android.telephony.CarrierConfigManager
import com.android.settingslib.SignalIcon.MobileIconGroup
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState.Connected
import com.android.systemui.statusbar.pipeline.mobile.data.model.DefaultNetworkType
import com.android.systemui.statusbar.pipeline.mobile.data.model.OverrideNetworkType
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository
import com.android.systemui.statusbar.pipeline.mobile.util.MobileMappingsProxy
import com.android.systemui.util.CarrierConfigTracker
-import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
-import kotlinx.coroutines.flow.flowOf
-import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.mapLatest
+import kotlinx.coroutines.flow.stateIn
interface MobileIconInteractor {
+ /** Only true if mobile is the default transport but is not validated, otherwise false */
+ val isDefaultConnectionFailed: StateFlow<Boolean>
+
+ /** True when telephony tells us that the data state is CONNECTED */
+ val isDataConnected: StateFlow<Boolean>
+
+ // TODO(b/256839546): clarify naming of default vs active
+ /** True if we want to consider the data connection enabled */
+ val isDefaultDataEnabled: StateFlow<Boolean>
+
/** Observable for the data enabled state of this connection */
- val isDataEnabled: Flow<Boolean>
+ val isDataEnabled: StateFlow<Boolean>
/** Observable for RAT type (network type) indicator */
- val networkTypeIconGroup: Flow<MobileIconGroup>
+ val networkTypeIconGroup: StateFlow<MobileIconGroup>
/** True if this line of service is emergency-only */
- val isEmergencyOnly: Flow<Boolean>
+ val isEmergencyOnly: StateFlow<Boolean>
/** Int describing the connection strength. 0-4 OR 1-5. See [numberOfLevels] */
- val level: Flow<Int>
+ val level: StateFlow<Int>
/** Based on [CarrierConfigManager.KEY_INFLATE_SIGNAL_STRENGTH_BOOL], either 4 or 5 */
- val numberOfLevels: Flow<Int>
-
- /** True when we want to draw an icon that makes room for the exclamation mark */
- val cutOut: Flow<Boolean>
+ val numberOfLevels: StateFlow<Int>
}
/** Interactor for a single mobile connection. This connection _should_ have one subscription ID */
+@Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
+@OptIn(ExperimentalCoroutinesApi::class)
class MobileIconInteractorImpl(
- defaultMobileIconMapping: Flow<Map<String, MobileIconGroup>>,
- defaultMobileIconGroup: Flow<MobileIconGroup>,
+ @Application scope: CoroutineScope,
+ defaultSubscriptionHasDataEnabled: StateFlow<Boolean>,
+ defaultMobileIconMapping: StateFlow<Map<String, MobileIconGroup>>,
+ defaultMobileIconGroup: StateFlow<MobileIconGroup>,
+ override val isDefaultConnectionFailed: StateFlow<Boolean>,
mobileMappingsProxy: MobileMappingsProxy,
connectionRepository: MobileConnectionRepository,
) : MobileIconInteractor {
private val mobileStatusInfo = connectionRepository.subscriptionModelFlow
- override val isDataEnabled: Flow<Boolean> = connectionRepository.dataEnabled
+ override val isDataEnabled: StateFlow<Boolean> = connectionRepository.dataEnabled
+
+ override val isDefaultDataEnabled = defaultSubscriptionHasDataEnabled
/** Observable for the current RAT indicator icon ([MobileIconGroup]) */
- override val networkTypeIconGroup: Flow<MobileIconGroup> =
+ override val networkTypeIconGroup: StateFlow<MobileIconGroup> =
combine(
- mobileStatusInfo,
- defaultMobileIconMapping,
- defaultMobileIconGroup,
- ) { info, mapping, defaultGroup ->
- val lookupKey =
- when (val resolved = info.resolvedNetworkType) {
- is DefaultNetworkType -> mobileMappingsProxy.toIconKey(resolved.type)
- is OverrideNetworkType -> mobileMappingsProxy.toIconKeyOverride(resolved.type)
- }
- mapping[lookupKey] ?: defaultGroup
- }
-
- override val isEmergencyOnly: Flow<Boolean> = mobileStatusInfo.map { it.isEmergencyOnly }
-
- override val level: Flow<Int> =
- mobileStatusInfo.map { mobileModel ->
- // TODO: incorporate [MobileMappings.Config.alwaysShowCdmaRssi]
- if (mobileModel.isGsm) {
- mobileModel.primaryLevel
- } else {
- mobileModel.cdmaLevel
+ mobileStatusInfo,
+ defaultMobileIconMapping,
+ defaultMobileIconGroup,
+ ) { info, mapping, defaultGroup ->
+ val lookupKey =
+ when (val resolved = info.resolvedNetworkType) {
+ is DefaultNetworkType -> mobileMappingsProxy.toIconKey(resolved.type)
+ is OverrideNetworkType ->
+ mobileMappingsProxy.toIconKeyOverride(resolved.type)
+ }
+ mapping[lookupKey] ?: defaultGroup
}
- }
+ .stateIn(scope, SharingStarted.WhileSubscribed(), defaultMobileIconGroup.value)
+
+ override val isEmergencyOnly: StateFlow<Boolean> =
+ mobileStatusInfo
+ .mapLatest { it.isEmergencyOnly }
+ .stateIn(scope, SharingStarted.WhileSubscribed(), false)
+
+ override val level: StateFlow<Int> =
+ mobileStatusInfo
+ .mapLatest { mobileModel ->
+ // TODO: incorporate [MobileMappings.Config.alwaysShowCdmaRssi]
+ if (mobileModel.isGsm) {
+ mobileModel.primaryLevel
+ } else {
+ mobileModel.cdmaLevel
+ }
+ }
+ .stateIn(scope, SharingStarted.WhileSubscribed(), 0)
/**
* This will become variable based on [CarrierConfigManager.KEY_INFLATE_SIGNAL_STRENGTH_BOOL]
* once it's wired up inside of [CarrierConfigTracker]
*/
- override val numberOfLevels: Flow<Int> = flowOf(4)
+ override val numberOfLevels: StateFlow<Int> = MutableStateFlow(4)
- /** Whether or not to draw the mobile triangle as "cut out", i.e., with the exclamation mark */
- // TODO: find a better name for this?
- override val cutOut: Flow<Boolean> = flowOf(false)
+ override val isDataConnected: StateFlow<Boolean> =
+ mobileStatusInfo
+ .mapLatest { subscriptionModel -> subscriptionModel.dataConnectionState == Connected }
+ .stateIn(scope, SharingStarted.WhileSubscribed(), false)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt
index 614d583..a4175c3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt
@@ -19,6 +19,7 @@
import android.telephony.CarrierConfigManager
import android.telephony.SubscriptionInfo
import android.telephony.SubscriptionManager
+import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID
import com.android.settingslib.SignalIcon.MobileIconGroup
import com.android.settingslib.mobile.TelephonyIcons
import com.android.systemui.dagger.SysUISingleton
@@ -35,7 +36,9 @@
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
-import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.mapLatest
import kotlinx.coroutines.flow.stateIn
/**
@@ -51,12 +54,16 @@
interface MobileIconsInteractor {
/** List of subscriptions, potentially filtered for CBRS */
val filteredSubscriptions: Flow<List<SubscriptionInfo>>
+ /** True if the active mobile data subscription has data enabled */
+ val activeDataConnectionHasDataEnabled: StateFlow<Boolean>
/** The icon mapping from network type to [MobileIconGroup] for the default subscription */
- val defaultMobileIconMapping: Flow<Map<String, MobileIconGroup>>
+ val defaultMobileIconMapping: StateFlow<Map<String, MobileIconGroup>>
/** Fallback [MobileIconGroup] in the case where there is no icon in the mapping */
- val defaultMobileIconGroup: Flow<MobileIconGroup>
+ val defaultMobileIconGroup: StateFlow<MobileIconGroup>
+ /** True only if the default network is mobile, and validation also failed */
+ val isDefaultConnectionFailed: StateFlow<Boolean>
/** True once the user has been set up */
- val isUserSetup: Flow<Boolean>
+ val isUserSetup: StateFlow<Boolean>
/**
* Vends out a [MobileIconInteractor] tracking the [MobileConnectionRepository] for the given
* subId. Will throw if the ID is invalid
@@ -79,6 +86,22 @@
private val activeMobileDataSubscriptionId =
mobileConnectionsRepo.activeMobileDataSubscriptionId
+ private val activeMobileDataConnectionRepo: StateFlow<MobileConnectionRepository?> =
+ activeMobileDataSubscriptionId
+ .mapLatest { activeId ->
+ if (activeId == INVALID_SUBSCRIPTION_ID) {
+ null
+ } else {
+ mobileConnectionsRepo.getRepoForSubId(activeId)
+ }
+ }
+ .stateIn(scope, SharingStarted.WhileSubscribed(), null)
+
+ override val activeDataConnectionHasDataEnabled: StateFlow<Boolean> =
+ activeMobileDataConnectionRepo
+ .flatMapLatest { it?.dataEnabled ?: flowOf(false) }
+ .stateIn(scope, SharingStarted.WhileSubscribed(), false)
+
private val unfilteredSubscriptions: Flow<List<SubscriptionInfo>> =
mobileConnectionsRepo.subscriptionsFlow
@@ -132,22 +155,40 @@
*/
override val defaultMobileIconMapping: StateFlow<Map<String, MobileIconGroup>> =
mobileConnectionsRepo.defaultDataSubRatConfig
- .map { mobileMappingsProxy.mapIconSets(it) }
+ .mapLatest { mobileMappingsProxy.mapIconSets(it) }
.stateIn(scope, SharingStarted.WhileSubscribed(), initialValue = mapOf())
/** If there is no mapping in [defaultMobileIconMapping], then use this default icon group */
override val defaultMobileIconGroup: StateFlow<MobileIconGroup> =
mobileConnectionsRepo.defaultDataSubRatConfig
- .map { mobileMappingsProxy.getDefaultIcons(it) }
+ .mapLatest { mobileMappingsProxy.getDefaultIcons(it) }
.stateIn(scope, SharingStarted.WhileSubscribed(), initialValue = TelephonyIcons.G)
- override val isUserSetup: Flow<Boolean> = userSetupRepo.isUserSetupFlow
+ /**
+ * We want to show an error state when cellular has actually failed to validate, but not if some
+ * other transport type is active, because then we expect there not to be validation.
+ */
+ override val isDefaultConnectionFailed: StateFlow<Boolean> =
+ mobileConnectionsRepo.defaultMobileNetworkConnectivity
+ .mapLatest { connectivityModel ->
+ if (!connectivityModel.isConnected) {
+ false
+ } else {
+ !connectivityModel.isValidated
+ }
+ }
+ .stateIn(scope, SharingStarted.WhileSubscribed(), false)
+
+ override val isUserSetup: StateFlow<Boolean> = userSetupRepo.isUserSetupFlow
/** Vends out new [MobileIconInteractor] for a particular subId */
override fun createMobileConnectionInteractorForSubId(subId: Int): MobileIconInteractor =
MobileIconInteractorImpl(
+ scope,
+ activeDataConnectionHasDataEnabled,
defaultMobileIconMapping,
defaultMobileIconGroup,
+ isDefaultConnectionFailed,
mobileMappingsProxy,
mobileConnectionsRepo.getRepoForSubId(subId),
)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModel.kt
index 8131739..7869021 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModel.kt
@@ -24,10 +24,12 @@
import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractor
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.logOutputChange
+import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.mapLatest
/**
* View model for the state of a single mobile icon. Each [MobileIconViewModel] will keep watch over
@@ -39,29 +41,38 @@
*
* TODO: figure out where carrier merged and VCN models go (probably here?)
*/
+@Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
+@OptIn(ExperimentalCoroutinesApi::class)
class MobileIconViewModel
constructor(
val subscriptionId: Int,
iconInteractor: MobileIconInteractor,
logger: ConnectivityPipelineLogger,
) {
+ /** Whether or not to show the error state of [SignalDrawable] */
+ private val showExclamationMark: Flow<Boolean> =
+ iconInteractor.isDefaultDataEnabled.mapLatest { !it }
+
/** An int consumable by [SignalDrawable] for display */
- var iconId: Flow<Int> =
- combine(iconInteractor.level, iconInteractor.numberOfLevels, iconInteractor.cutOut) {
+ val iconId: Flow<Int> =
+ combine(iconInteractor.level, iconInteractor.numberOfLevels, showExclamationMark) {
level,
numberOfLevels,
- cutOut ->
- SignalDrawable.getState(level, numberOfLevels, cutOut)
+ showExclamationMark ->
+ SignalDrawable.getState(level, numberOfLevels, showExclamationMark)
}
.distinctUntilChanged()
.logOutputChange(logger, "iconId($subscriptionId)")
/** The RAT icon (LTE, 3G, 5G, etc) to be displayed. Null if we shouldn't show anything */
- var networkTypeIcon: Flow<Icon?> =
- combine(iconInteractor.networkTypeIconGroup, iconInteractor.isDataEnabled) {
- networkTypeIconGroup,
- isDataEnabled ->
- if (!isDataEnabled) {
+ val networkTypeIcon: Flow<Icon?> =
+ combine(
+ iconInteractor.networkTypeIconGroup,
+ iconInteractor.isDataConnected,
+ iconInteractor.isDataEnabled,
+ iconInteractor.isDefaultConnectionFailed,
+ ) { networkTypeIconGroup, dataConnected, dataEnabled, failedConnection ->
+ if (!dataConnected || !dataEnabled || failedConnection) {
null
} else {
val desc =
@@ -72,5 +83,5 @@
}
}
- var tint: Flow<Int> = flowOf(Color.CYAN)
+ val tint: Flow<Int> = flowOf(Color.CYAN)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceControlsControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceControlsControllerImpl.kt
index bc2ae64..e326611 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceControlsControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceControlsControllerImpl.kt
@@ -67,7 +67,7 @@
internal const val QS_DEFAULT_POSITION = 7
internal const val PREFS_CONTROLS_SEEDING_COMPLETED = "SeedingCompleted"
- internal const val PREFS_CONTROLS_FILE = "controls_prefs"
+ const val PREFS_CONTROLS_FILE = "controls_prefs"
internal const val PREFS_SETTINGS_DIALOG_ATTEMPTS = "show_settings_attempts"
private const val SEEDING_MAX = 2
}
diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
index 3ecb15b..5894fd3 100644
--- a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
+++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
@@ -115,7 +115,6 @@
private final SecureSettings mSecureSettings;
private final Executor mMainExecutor;
private final Handler mBgHandler;
- private final boolean mIsMonochromaticEnabled;
private final Context mContext;
private final boolean mIsMonetEnabled;
private final UserTracker mUserTracker;
@@ -365,7 +364,6 @@
UserTracker userTracker, DumpManager dumpManager, FeatureFlags featureFlags,
@Main Resources resources, WakefulnessLifecycle wakefulnessLifecycle) {
mContext = context;
- mIsMonochromaticEnabled = featureFlags.isEnabled(Flags.MONOCHROMATIC_THEMES);
mIsMonetEnabled = featureFlags.isEnabled(Flags.MONET);
mDeviceProvisionedController = deviceProvisionedController;
mBroadcastDispatcher = broadcastDispatcher;
@@ -669,11 +667,8 @@
// used as a system-wide theme.
// - Content intentionally excluded, intended for media player, not system-wide
List<Style> validStyles = new ArrayList<>(Arrays.asList(Style.EXPRESSIVE, Style.SPRITZ,
- Style.TONAL_SPOT, Style.FRUIT_SALAD, Style.RAINBOW, Style.VIBRANT));
-
- if (mIsMonochromaticEnabled) {
- validStyles.add(Style.MONOCHROMATIC);
- }
+ Style.TONAL_SPOT, Style.FRUIT_SALAD, Style.RAINBOW, Style.VIBRANT,
+ Style.MONOCHROMATIC));
Style style = mThemeStyle;
final String overlayPackageJson = mSecureSettings.getStringForUser(
diff --git a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java
index 10a09dd1..61eadeb 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java
@@ -44,6 +44,7 @@
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.RecentsImplementation;
import com.android.systemui.screenshot.ReferenceScreenshotModule;
+import com.android.systemui.settings.dagger.MultiUserUtilsModule;
import com.android.systemui.shade.NotificationShadeWindowControllerImpl;
import com.android.systemui.shade.ShadeController;
import com.android.systemui.shade.ShadeControllerImpl;
@@ -89,6 +90,7 @@
includes = {
AospPolicyModule.class,
GestureModule.class,
+ MultiUserUtilsModule.class,
PowerModule.class,
QSModule.class,
ReferenceScreenshotModule.class,
diff --git a/packages/SystemUI/src/com/android/systemui/user/data/repository/UserRepository.kt b/packages/SystemUI/src/com/android/systemui/user/data/repository/UserRepository.kt
index b16dc54..6a23260 100644
--- a/packages/SystemUI/src/com/android/systemui/user/data/repository/UserRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/user/data/repository/UserRepository.kt
@@ -62,6 +62,7 @@
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.launch
+import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext
/**
@@ -136,7 +137,7 @@
private val isNewImpl: Boolean
get() = !featureFlags.isEnabled(Flags.USER_INTERACTOR_AND_REPO_USE_CONTROLLER)
- private val _userSwitcherSettings = MutableStateFlow<UserSwitcherSettingsModel?>(null)
+ private val _userSwitcherSettings = MutableStateFlow(runBlocking { getSettings() })
override val userSwitcherSettings: Flow<UserSwitcherSettingsModel> =
_userSwitcherSettings.asStateFlow().filterNotNull()
@@ -235,7 +236,7 @@
}
override fun isSimpleUserSwitcher(): Boolean {
- return checkNotNull(_userSwitcherSettings.value?.isSimpleUserSwitcher)
+ return _userSwitcherSettings.value.isSimpleUserSwitcher
}
private fun observeSelectedUser() {
diff --git a/packages/SystemUI/src/com/android/systemui/user/domain/interactor/GuestUserInteractor.kt b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/GuestUserInteractor.kt
index 07e5cf9..f9d14cd 100644
--- a/packages/SystemUI/src/com/android/systemui/user/domain/interactor/GuestUserInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/GuestUserInteractor.kt
@@ -208,7 +208,12 @@
if (newGuestId == UserHandle.USER_NULL) {
Log.e(TAG, "Could not create new guest, switching back to system user")
switchUser(UserHandle.USER_SYSTEM)
- withContext(backgroundDispatcher) { manager.removeUser(currentUser.id) }
+ withContext(backgroundDispatcher) {
+ manager.removeUserWhenPossible(
+ UserHandle.of(currentUser.id),
+ /* overrideDevicePolicy= */ false
+ )
+ }
try {
WindowManagerGlobal.getWindowManagerService().lockNow(/* options= */ null)
} catch (e: RemoteException) {
@@ -222,13 +227,21 @@
switchUser(newGuestId)
- withContext(backgroundDispatcher) { manager.removeUser(currentUser.id) }
+ withContext(backgroundDispatcher) {
+ manager.removeUserWhenPossible(
+ UserHandle.of(currentUser.id),
+ /* overrideDevicePolicy= */ false
+ )
+ }
} else {
if (repository.isGuestUserAutoCreated) {
repository.isGuestUserResetting = true
}
switchUser(targetUserId)
- manager.removeUser(currentUser.id)
+ manager.removeUserWhenPossible(
+ UserHandle.of(currentUser.id),
+ /* overrideDevicePolicy= */ false
+ )
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/user/ui/binder/UserSwitcherViewBinder.kt b/packages/SystemUI/src/com/android/systemui/user/ui/binder/UserSwitcherViewBinder.kt
index 968af59..ad09ee3 100644
--- a/packages/SystemUI/src/com/android/systemui/user/ui/binder/UserSwitcherViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/user/ui/binder/UserSwitcherViewBinder.kt
@@ -61,14 +61,15 @@
falsingCollector: FalsingCollector,
onFinish: () -> Unit,
) {
- val rootView: UserSwitcherRootView = view.requireViewById(R.id.user_switcher_root)
- val flowWidget: FlowWidget = view.requireViewById(R.id.flow)
+ val gridContainerView: UserSwitcherRootView =
+ view.requireViewById(R.id.user_switcher_grid_container)
+ val flowWidget: FlowWidget = gridContainerView.requireViewById(R.id.flow)
val addButton: View = view.requireViewById(R.id.add)
val cancelButton: View = view.requireViewById(R.id.cancel)
val popupMenuAdapter = MenuAdapter(layoutInflater)
var popupMenu: UserSwitcherPopupMenu? = null
- rootView.touchHandler =
+ gridContainerView.touchHandler =
object : Gefingerpoken {
override fun onTouchEvent(ev: MotionEvent?): Boolean {
falsingCollector.onTouchEvent(ev)
@@ -134,7 +135,7 @@
val viewPool =
view.children.filter { it.tag == USER_VIEW_TAG }.toMutableList()
viewPool.forEach {
- view.removeView(it)
+ gridContainerView.removeView(it)
flowWidget.removeView(it)
}
users.forEach { userViewModel ->
@@ -152,7 +153,7 @@
inflatedView
}
userView.id = View.generateViewId()
- view.addView(userView)
+ gridContainerView.addView(userView)
flowWidget.addView(userView)
UserViewBinder.bind(
view = userView,
diff --git a/packages/SystemUI/src/com/android/systemui/wallpapers/ImageWallpaper.java b/packages/SystemUI/src/com/android/systemui/wallpapers/ImageWallpaper.java
index 44f6d03..ad97ef4 100644
--- a/packages/SystemUI/src/com/android/systemui/wallpapers/ImageWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/wallpapers/ImageWallpaper.java
@@ -31,6 +31,7 @@
import android.os.HandlerThread;
import android.os.SystemClock;
import android.os.Trace;
+import android.os.UserHandle;
import android.service.wallpaper.WallpaperService;
import android.util.ArraySet;
import android.util.Log;
@@ -598,7 +599,6 @@
getDisplayContext().getSystemService(DisplayManager.class)
.unregisterDisplayListener(this);
mWallpaperLocalColorExtractor.cleanUp();
- unloadBitmap();
}
@Override
@@ -676,9 +676,14 @@
void drawFrameOnCanvas(Bitmap bitmap) {
Trace.beginSection("ImageWallpaper.CanvasEngine#drawFrame");
Surface surface = mSurfaceHolder.getSurface();
- Canvas canvas = mWideColorGamut
- ? surface.lockHardwareWideColorGamutCanvas()
- : surface.lockHardwareCanvas();
+ Canvas canvas = null;
+ try {
+ canvas = mWideColorGamut
+ ? surface.lockHardwareWideColorGamutCanvas()
+ : surface.lockHardwareCanvas();
+ } catch (IllegalStateException e) {
+ Log.w(TAG, "Unable to lock canvas", e);
+ }
if (canvas != null) {
Rect dest = mSurfaceHolder.getSurfaceFrame();
try {
@@ -709,17 +714,6 @@
}
}
- private void unloadBitmap() {
- mBackgroundExecutor.execute(this::unloadBitmapSynchronized);
- }
-
- private void unloadBitmapSynchronized() {
- synchronized (mLock) {
- mBitmapUsages = 0;
- unloadBitmapInternal();
- }
- }
-
private void unloadBitmapInternal() {
Trace.beginSection("ImageWallpaper.CanvasEngine#unloadBitmap");
if (mBitmap != null) {
@@ -738,7 +732,7 @@
boolean loadSuccess = false;
Bitmap bitmap;
try {
- bitmap = mWallpaperManager.getBitmap(false);
+ bitmap = mWallpaperManager.getBitmapAsUser(UserHandle.USER_CURRENT, false);
if (bitmap != null
&& bitmap.getByteCount() > RecordingCanvas.MAX_BITMAP_SIZE) {
throw new RuntimeException("Wallpaper is too large to draw!");
@@ -757,7 +751,7 @@
}
try {
- bitmap = mWallpaperManager.getBitmap(false);
+ bitmap = mWallpaperManager.getBitmapAsUser(UserHandle.USER_CURRENT, false);
} catch (RuntimeException | OutOfMemoryError e) {
Log.w(TAG, "Unable to load default wallpaper!", e);
bitmap = null;
@@ -770,9 +764,6 @@
Log.e(TAG, "Attempt to load a recycled bitmap");
} else if (mBitmap == bitmap) {
Log.e(TAG, "Loaded a bitmap that was already loaded");
- } else if (bitmap.getWidth() < 1 || bitmap.getHeight() < 1) {
- Log.e(TAG, "Attempt to load an invalid wallpaper of length "
- + bitmap.getWidth() + "x" + bitmap.getHeight());
} else {
// at this point, loading is done correctly.
loadSuccess = true;
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt
index 1c3656d..52b6b38 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt
@@ -65,7 +65,6 @@
class ClockEventControllerTest : SysuiTestCase() {
@JvmField @Rule val mockito = MockitoJUnit.rule()
- @Mock private lateinit var keyguardInteractor: KeyguardInteractor
@Mock private lateinit var broadcastDispatcher: BroadcastDispatcher
@Mock private lateinit var batteryController: BatteryController
@Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java
index f9bec65..52f8ef8 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java
@@ -55,6 +55,7 @@
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.biometrics.SidefpsController;
+import com.android.systemui.classifier.FalsingA11yDelegate;
import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.log.SessionTracker;
@@ -143,6 +144,8 @@
private SidefpsController mSidefpsController;
@Mock
private KeyguardPasswordViewController mKeyguardPasswordViewControllerMock;
+ @Mock
+ private FalsingA11yDelegate mFalsingA11yDelegate;
@Captor
private ArgumentCaptor<KeyguardUpdateMonitorCallback> mKeyguardUpdateMonitorCallback;
@@ -186,7 +189,8 @@
mKeyguardStateController, mKeyguardSecurityViewFlipperController,
mConfigurationController, mFalsingCollector, mFalsingManager,
mUserSwitcherController, mFeatureFlags, mGlobalSettings,
- mSessionTracker, Optional.of(mSidefpsController)).create(mSecurityCallback);
+ mSessionTracker, Optional.of(mSidefpsController), mFalsingA11yDelegate).create(
+ mSecurityCallback);
}
@Test
@@ -225,7 +229,8 @@
mKeyguardSecurityContainerController.updateResources();
verify(mView, never()).initMode(eq(MODE_DEFAULT), eq(mGlobalSettings), eq(mFalsingManager),
eq(mUserSwitcherController),
- any(KeyguardSecurityContainer.UserSwitcherViewMode.UserSwitcherCallback.class));
+ any(KeyguardSecurityContainer.UserSwitcherViewMode.UserSwitcherCallback.class),
+ eq(mFalsingA11yDelegate));
// Update rotation. Should trigger update
mConfiguration.orientation = Configuration.ORIENTATION_LANDSCAPE;
@@ -233,7 +238,8 @@
mKeyguardSecurityContainerController.updateResources();
verify(mView).initMode(eq(MODE_DEFAULT), eq(mGlobalSettings), eq(mFalsingManager),
eq(mUserSwitcherController),
- any(KeyguardSecurityContainer.UserSwitcherViewMode.UserSwitcherCallback.class));
+ any(KeyguardSecurityContainer.UserSwitcherViewMode.UserSwitcherCallback.class),
+ eq(mFalsingA11yDelegate));
}
private void touchDown() {
@@ -269,7 +275,8 @@
mKeyguardSecurityContainerController.showSecurityScreen(SecurityMode.Pattern);
verify(mView).initMode(eq(MODE_DEFAULT), eq(mGlobalSettings), eq(mFalsingManager),
eq(mUserSwitcherController),
- any(KeyguardSecurityContainer.UserSwitcherViewMode.UserSwitcherCallback.class));
+ any(KeyguardSecurityContainer.UserSwitcherViewMode.UserSwitcherCallback.class),
+ eq(mFalsingA11yDelegate));
}
@Test
@@ -282,7 +289,8 @@
mKeyguardSecurityContainerController.showSecurityScreen(SecurityMode.Pattern);
verify(mView).initMode(eq(MODE_ONE_HANDED), eq(mGlobalSettings), eq(mFalsingManager),
eq(mUserSwitcherController),
- any(KeyguardSecurityContainer.UserSwitcherViewMode.UserSwitcherCallback.class));
+ any(KeyguardSecurityContainer.UserSwitcherViewMode.UserSwitcherCallback.class),
+ eq(mFalsingA11yDelegate));
}
@Test
@@ -293,7 +301,8 @@
mKeyguardSecurityContainerController.showSecurityScreen(SecurityMode.Password);
verify(mView).initMode(eq(MODE_DEFAULT), eq(mGlobalSettings), eq(mFalsingManager),
eq(mUserSwitcherController),
- any(KeyguardSecurityContainer.UserSwitcherViewMode.UserSwitcherCallback.class));
+ any(KeyguardSecurityContainer.UserSwitcherViewMode.UserSwitcherCallback.class),
+ eq(mFalsingA11yDelegate));
}
@Test
@@ -307,7 +316,8 @@
mKeyguardSecurityContainerController.showSecurityScreen(SecurityMode.Password);
verify(mView).initMode(anyInt(), any(GlobalSettings.class), any(FalsingManager.class),
any(UserSwitcherController.class),
- captor.capture());
+ captor.capture(),
+ eq(mFalsingA11yDelegate));
captor.getValue().showUnlockToContinueMessage();
verify(mKeyguardPasswordViewControllerMock).showMessage(
getContext().getString(R.string.keyguard_unlock_to_continue), null);
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java
index 82d3ca7..1bd14e5 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java
@@ -31,6 +31,7 @@
import static com.android.keyguard.KeyguardSecurityContainer.MODE_DEFAULT;
import static com.android.keyguard.KeyguardSecurityContainer.MODE_ONE_HANDED;
+import static com.android.keyguard.KeyguardSecurityContainer.MODE_USER_SWITCHER;
import static com.google.common.truth.Truth.assertThat;
@@ -54,6 +55,7 @@
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.classifier.FalsingA11yDelegate;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.statusbar.policy.UserSwitcherController;
import com.android.systemui.user.data.source.UserRecord;
@@ -87,6 +89,8 @@
private FalsingManager mFalsingManager;
@Mock
private UserSwitcherController mUserSwitcherController;
+ @Mock
+ private FalsingA11yDelegate mFalsingA11yDelegate;
private KeyguardSecurityContainer mKeyguardSecurityContainer;
@@ -111,15 +115,14 @@
when(mUserSwitcherController.getCurrentUserName()).thenReturn("Test User");
when(mUserSwitcherController.isKeyguardShowing()).thenReturn(true);
}
+
@Test
public void testOnApplyWindowInsets() {
int paddingBottom = getContext().getResources()
.getDimensionPixelSize(R.dimen.keyguard_security_view_bottom_margin);
int imeInsetAmount = paddingBottom + 1;
int systemBarInsetAmount = 0;
-
- mKeyguardSecurityContainer.initMode(MODE_DEFAULT, mGlobalSettings, mFalsingManager,
- mUserSwitcherController, () -> {});
+ initMode(MODE_DEFAULT);
Insets imeInset = Insets.of(0, 0, 0, imeInsetAmount);
Insets systemBarInset = Insets.of(0, 0, 0, systemBarInsetAmount);
@@ -140,8 +143,7 @@
.getDimensionPixelSize(R.dimen.keyguard_security_view_bottom_margin);
int systemBarInsetAmount = paddingBottom + 1;
- mKeyguardSecurityContainer.initMode(MODE_DEFAULT, mGlobalSettings, mFalsingManager,
- mUserSwitcherController, () -> {});
+ initMode(MODE_DEFAULT);
Insets imeInset = Insets.of(0, 0, 0, imeInsetAmount);
Insets systemBarInset = Insets.of(0, 0, 0, systemBarInsetAmount);
@@ -157,11 +159,8 @@
@Test
public void testDefaultViewMode() {
- mKeyguardSecurityContainer.initMode(MODE_ONE_HANDED, mGlobalSettings, mFalsingManager,
- mUserSwitcherController, () -> {
- });
- mKeyguardSecurityContainer.initMode(MODE_DEFAULT, mGlobalSettings, mFalsingManager,
- mUserSwitcherController, () -> {});
+ initMode(MODE_ONE_HANDED);
+ initMode(MODE_DEFAULT);
ConstraintSet.Constraint viewFlipperConstraint =
getViewConstraint(mSecurityViewFlipper.getId());
assertThat(viewFlipperConstraint.layout.topToTop).isEqualTo(PARENT_ID);
@@ -377,8 +376,7 @@
private void setupUserSwitcher() {
when(mGlobalSettings.getInt(any(), anyInt())).thenReturn(ONE_HANDED_KEYGUARD_SIDE_RIGHT);
- mKeyguardSecurityContainer.initMode(KeyguardSecurityContainer.MODE_USER_SWITCHER,
- mGlobalSettings, mFalsingManager, mUserSwitcherController, () -> {});
+ initMode(MODE_USER_SWITCHER);
}
private ArrayList<UserRecord> buildUserRecords(int count) {
@@ -396,8 +394,7 @@
private void setupForUpdateKeyguardPosition(boolean oneHandedMode) {
int mode = oneHandedMode ? MODE_ONE_HANDED : MODE_DEFAULT;
- mKeyguardSecurityContainer.initMode(mode, mGlobalSettings, mFalsingManager,
- mUserSwitcherController, () -> {});
+ initMode(mode);
}
/** Get the ConstraintLayout constraint of the view. */
@@ -406,4 +403,10 @@
constraintSet.clone(mKeyguardSecurityContainer);
return constraintSet.getConstraint(viewId);
}
+
+ private void initMode(int mode) {
+ mKeyguardSecurityContainer.initMode(mode, mGlobalSettings, mFalsingManager,
+ mUserSwitcherController, () -> {
+ }, mFalsingA11yDelegate);
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/DismissAnimationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/DismissAnimationControllerTest.java
index 8ef65dc..a36105e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/DismissAnimationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/DismissAnimationControllerTest.java
@@ -16,6 +16,7 @@
package com.android.systemui.accessibility.floatingmenu;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import android.testing.AndroidTestingRunner;
@@ -47,7 +48,7 @@
stubWindowManager);
final MenuView stubMenuView = new MenuView(mContext, stubMenuViewModel,
stubMenuViewAppearance);
- mDismissView = new DismissView(mContext);
+ mDismissView = spy(new DismissView(mContext));
mDismissAnimationController = new DismissAnimationController(mDismissView, stubMenuView);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineFalsingManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineFalsingManagerTest.java
index 9481349..b811aab 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineFalsingManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineFalsingManagerTest.java
@@ -96,7 +96,6 @@
assertThat(mBrightLineFalsingManager.isFalseTap(1)).isFalse();
}
-
@Test
public void testA11yDisablesTap() {
assertThat(mBrightLineFalsingManager.isFalseTouch(Classifier.GENERIC)).isTrue();
@@ -159,4 +158,11 @@
});
assertThat(mBrightLineFalsingManager.isProximityNear()).isFalse();
}
+
+ @Test
+ public void testA11yAction() {
+ assertThat(mBrightLineFalsingManager.isFalseTap(1)).isTrue();
+ when(mFalsingDataProvider.isA11yAction()).thenReturn(true);
+ assertThat(mBrightLineFalsingManager.isFalseTap(1)).isFalse();
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingA11yDelegateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingA11yDelegateTest.kt
new file mode 100644
index 0000000..2c904e7
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingA11yDelegateTest.kt
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.classifier
+
+import android.testing.AndroidTestingRunner
+import android.view.View
+import android.view.accessibility.AccessibilityNodeInfo.ACTION_CLICK
+import android.view.accessibility.AccessibilityNodeInfo.ACTION_LONG_CLICK
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.never
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class FalsingA11yDelegateTest : SysuiTestCase() {
+ @Mock lateinit var falsingCollector: FalsingCollector
+ @Mock lateinit var view: View
+ lateinit var underTest: FalsingA11yDelegate
+
+ @Before
+ fun setup() {
+ MockitoAnnotations.initMocks(this)
+ underTest = FalsingA11yDelegate(falsingCollector)
+ }
+
+ @Test
+ fun testPerformAccessibilityAction_ACTION_CLICK() {
+ underTest.performAccessibilityAction(view, ACTION_CLICK, null)
+ verify(falsingCollector).onA11yAction()
+ }
+
+ @Test
+ fun testPerformAccessibilityAction_not_ACTION_CLICK() {
+ underTest.performAccessibilityAction(view, ACTION_LONG_CLICK, null)
+ verify(falsingCollector, never()).onA11yAction()
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingCollectorImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingCollectorImplTest.java
index fa9c41a..442bf91 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingCollectorImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingCollectorImplTest.java
@@ -267,4 +267,10 @@
mFalsingCollector.onTouchEvent(up);
verify(mFalsingDataProvider, times(2)).onMotionEvent(any(MotionEvent.class));
}
+
+ @Test
+ public void testOnA11yAction() {
+ mFalsingCollector.onA11yAction();
+ verify(mFalsingDataProvider).onA11yAction();
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingDataProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingDataProviderTest.java
index 5dc607f..d315c2d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingDataProviderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingDataProviderTest.java
@@ -310,4 +310,10 @@
// an empty array.
assertThat(mDataProvider.getPriorMotionEvents()).isNotNull();
}
+
+ @Test
+ public void test_MotionEventComplete_A11yAction() {
+ mDataProvider.onA11yAction();
+ assertThat(mDataProvider.isA11yAction()).isTrue();
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerTest.java
index b7f1c1a..a872e4b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerTest.java
@@ -19,7 +19,9 @@
import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_DISMISS_TAPPED;
import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_SHARE_TAPPED;
import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_SWIPE_DISMISSED;
+import static com.android.systemui.flags.Flags.CLIPBOARD_REMOTE_BEHAVIOR;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -37,6 +39,7 @@
import com.android.internal.logging.UiEventLogger;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.broadcast.BroadcastSender;
+import com.android.systemui.flags.FakeFeatureFlags;
import com.android.systemui.screenshot.TimeoutHandler;
import org.junit.After;
@@ -62,7 +65,10 @@
@Mock
private TimeoutHandler mTimeoutHandler;
@Mock
+ private ClipboardOverlayUtils mClipboardUtils;
+ @Mock
private UiEventLogger mUiEventLogger;
+ private FakeFeatureFlags mFeatureFlags = new FakeFeatureFlags();
@Mock
private Animator mAnimator;
@@ -73,7 +79,6 @@
private ArgumentCaptor<ClipboardOverlayView.ClipboardOverlayCallbacks> mOverlayCallbacksCaptor;
private ClipboardOverlayView.ClipboardOverlayCallbacks mCallbacks;
-
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
@@ -84,6 +89,8 @@
mSampleClipData = new ClipData("Test", new String[]{"text/plain"},
new ClipData.Item("Test Item"));
+ mFeatureFlags.set(CLIPBOARD_REMOTE_BEHAVIOR, false);
+
mOverlayController = new ClipboardOverlayController(
mContext,
mClipboardOverlayView,
@@ -91,6 +98,8 @@
getFakeBroadcastDispatcher(),
mBroadcastSender,
mTimeoutHandler,
+ mFeatureFlags,
+ mClipboardUtils,
mUiEventLogger);
verify(mClipboardOverlayView).setCallbacks(mOverlayCallbacksCaptor.capture());
mCallbacks = mOverlayCallbacksCaptor.getValue();
@@ -186,4 +195,33 @@
verify(mUiEventLogger, times(1)).log(CLIPBOARD_OVERLAY_SWIPE_DISMISSED);
verify(mUiEventLogger, never()).log(CLIPBOARD_OVERLAY_DISMISS_TAPPED);
}
+
+ @Test
+ public void test_remoteCopy_withFlagOn() {
+ mFeatureFlags.set(CLIPBOARD_REMOTE_BEHAVIOR, true);
+ when(mClipboardUtils.isRemoteCopy(any(), any(), any())).thenReturn(true);
+
+ mOverlayController.setClipData(mSampleClipData, "");
+
+ verify(mTimeoutHandler, never()).resetTimeout();
+ }
+
+ @Test
+ public void test_remoteCopy_withFlagOff() {
+ when(mClipboardUtils.isRemoteCopy(any(), any(), any())).thenReturn(true);
+
+ mOverlayController.setClipData(mSampleClipData, "");
+
+ verify(mTimeoutHandler).resetTimeout();
+ }
+
+ @Test
+ public void test_nonRemoteCopy() {
+ mFeatureFlags.set(CLIPBOARD_REMOTE_BEHAVIOR, true);
+ when(mClipboardUtils.isRemoteCopy(any(), any(), any())).thenReturn(false);
+
+ mOverlayController.setClipData(mSampleClipData, "");
+
+ verify(mTimeoutHandler).resetTimeout();
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayUtilsTest.java b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayUtilsTest.java
new file mode 100644
index 0000000..09b1699
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayUtilsTest.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.clipboardoverlay;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.content.ClipData;
+import android.content.ClipDescription;
+import android.os.PersistableBundle;
+import android.testing.TestableResources;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ClipboardOverlayUtilsTest extends SysuiTestCase {
+
+ private ClipboardOverlayUtils mClipboardUtils;
+
+ @Before
+ public void setUp() {
+ mClipboardUtils = new ClipboardOverlayUtils();
+ }
+
+ @Test
+ public void test_extra_withPackage_returnsTrue() {
+ PersistableBundle b = new PersistableBundle();
+ b.putBoolean(ClipDescription.EXTRA_IS_REMOTE_DEVICE, true);
+ ClipData data = constructClipData(
+ new String[]{"text/plain"}, new ClipData.Item("6175550000"), b);
+ TestableResources res = mContext.getOrCreateTestableResources();
+ res.addOverride(
+ R.string.config_remoteCopyPackage, "com.android.remote/.RemoteActivity");
+
+ assertTrue(mClipboardUtils.isRemoteCopy(mContext, data, "com.android.remote"));
+ }
+
+ @Test
+ public void test_noExtra_returnsFalse() {
+ ClipData data = constructClipData(
+ new String[]{"text/plain"}, new ClipData.Item("6175550000"), null);
+ TestableResources res = mContext.getOrCreateTestableResources();
+ res.addOverride(
+ R.string.config_remoteCopyPackage, "com.android.remote/.RemoteActivity");
+
+ assertFalse(mClipboardUtils.isRemoteCopy(mContext, data, "com.android.remote"));
+ }
+
+ @Test
+ public void test_falseExtra_returnsFalse() {
+ PersistableBundle b = new PersistableBundle();
+ b.putBoolean(ClipDescription.EXTRA_IS_REMOTE_DEVICE, false);
+ ClipData data = constructClipData(
+ new String[]{"text/plain"}, new ClipData.Item("6175550000"), b);
+ TestableResources res = mContext.getOrCreateTestableResources();
+ res.addOverride(
+ R.string.config_remoteCopyPackage, "com.android.remote/.RemoteActivity");
+
+ assertFalse(mClipboardUtils.isRemoteCopy(mContext, data, "com.android.remote"));
+ }
+
+ @Test
+ public void test_wrongPackage_returnsFalse() {
+ PersistableBundle b = new PersistableBundle();
+ b.putBoolean(ClipDescription.EXTRA_IS_REMOTE_DEVICE, true);
+ ClipData data = constructClipData(
+ new String[]{"text/plain"}, new ClipData.Item("6175550000"), b);
+
+ assertFalse(mClipboardUtils.isRemoteCopy(mContext, data, ""));
+ }
+
+ static ClipData constructClipData(String[] mimeTypes, ClipData.Item item,
+ PersistableBundle extras) {
+ ClipDescription description = new ClipDescription("Test", mimeTypes);
+ if (extras != null) {
+ description.setExtras(extras);
+ }
+ return new ClipData(description, item);
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsUiControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsUiControllerImplTest.kt
new file mode 100644
index 0000000..49c7442
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlsUiControllerImplTest.kt
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.controls.ui
+
+import android.content.ComponentName
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.controls.ControlsMetricsLogger
+import com.android.systemui.controls.CustomIconCache
+import com.android.systemui.controls.controller.ControlsController
+import com.android.systemui.controls.controller.StructureInfo
+import com.android.systemui.controls.management.ControlsListingController
+import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.settings.UserFileManager
+import com.android.systemui.settings.UserTracker
+import com.android.systemui.shade.ShadeController
+import com.android.systemui.statusbar.policy.DeviceControlsControllerImpl
+import com.android.systemui.statusbar.policy.KeyguardStateController
+import com.android.systemui.util.FakeSharedPreferences
+import com.android.systemui.util.concurrency.FakeExecutor
+import com.android.systemui.util.time.FakeSystemClock
+import com.google.common.truth.Truth.assertThat
+import dagger.Lazy
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.anyInt
+import org.mockito.Mockito.anyString
+import org.mockito.Mockito.mock
+import org.mockito.Mockito.times
+import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when`
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper
+class ControlsUiControllerImplTest : SysuiTestCase() {
+ @Mock lateinit var controlsController: ControlsController
+ @Mock lateinit var controlsListingController: ControlsListingController
+ @Mock lateinit var controlActionCoordinator: ControlActionCoordinator
+ @Mock lateinit var activityStarter: ActivityStarter
+ @Mock lateinit var shadeController: ShadeController
+ @Mock lateinit var iconCache: CustomIconCache
+ @Mock lateinit var controlsMetricsLogger: ControlsMetricsLogger
+ @Mock lateinit var keyguardStateController: KeyguardStateController
+ @Mock lateinit var userFileManager: UserFileManager
+ @Mock lateinit var userTracker: UserTracker
+ val sharedPreferences = FakeSharedPreferences()
+
+ var uiExecutor = FakeExecutor(FakeSystemClock())
+ var bgExecutor = FakeExecutor(FakeSystemClock())
+ lateinit var underTest: ControlsUiControllerImpl
+
+ @Before
+ fun setup() {
+ MockitoAnnotations.initMocks(this)
+
+ underTest =
+ ControlsUiControllerImpl(
+ Lazy { controlsController },
+ context,
+ uiExecutor,
+ bgExecutor,
+ Lazy { controlsListingController },
+ controlActionCoordinator,
+ activityStarter,
+ shadeController,
+ iconCache,
+ controlsMetricsLogger,
+ keyguardStateController,
+ userFileManager,
+ userTracker
+ )
+ `when`(
+ userFileManager.getSharedPreferences(
+ DeviceControlsControllerImpl.PREFS_CONTROLS_FILE,
+ 0,
+ 0
+ )
+ )
+ .thenReturn(sharedPreferences)
+ `when`(userFileManager.getSharedPreferences(anyString(), anyInt(), anyInt()))
+ .thenReturn(sharedPreferences)
+ `when`(userTracker.userId).thenReturn(0)
+ }
+
+ @Test
+ fun testGetPreferredStructure() {
+ val structureInfo = mock(StructureInfo::class.java)
+ underTest.getPreferredStructure(listOf(structureInfo))
+ verify(userFileManager, times(2))
+ .getSharedPreferences(
+ fileName = DeviceControlsControllerImpl.PREFS_CONTROLS_FILE,
+ mode = 0,
+ userId = 0
+ )
+ }
+
+ @Test
+ fun testGetPreferredStructure_differentUserId() {
+ val structureInfo =
+ listOf(
+ StructureInfo(ComponentName.unflattenFromString("pkg/.cls1"), "a", ArrayList()),
+ StructureInfo(ComponentName.unflattenFromString("pkg/.cls2"), "b", ArrayList()),
+ )
+ sharedPreferences
+ .edit()
+ .putString("controls_component", structureInfo[0].componentName.flattenToString())
+ .putString("controls_structure", structureInfo[0].structure.toString())
+ .commit()
+
+ val differentSharedPreferences = FakeSharedPreferences()
+ differentSharedPreferences
+ .edit()
+ .putString("controls_component", structureInfo[1].componentName.flattenToString())
+ .putString("controls_structure", structureInfo[1].structure.toString())
+ .commit()
+
+ val previousPreferredStructure = underTest.getPreferredStructure(structureInfo)
+
+ `when`(
+ userFileManager.getSharedPreferences(
+ DeviceControlsControllerImpl.PREFS_CONTROLS_FILE,
+ 0,
+ 1
+ )
+ )
+ .thenReturn(differentSharedPreferences)
+ `when`(userTracker.userId).thenReturn(1)
+
+ val currentPreferredStructure = underTest.getPreferredStructure(structureInfo)
+
+ assertThat(previousPreferredStructure).isEqualTo(structureInfo[0])
+ assertThat(currentPreferredStructure).isEqualTo(structureInfo[1])
+ assertThat(currentPreferredStructure).isNotEqualTo(previousPreferredStructure)
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt
index 7a15680..b9ab9d3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt
@@ -20,6 +20,8 @@
import com.android.systemui.SysuiTestCase
import com.android.systemui.common.shared.model.Position
import com.android.systemui.doze.DozeHost
+import com.android.systemui.keyguard.WakefulnessLifecycle
+import com.android.systemui.keyguard.shared.model.WakefulnessModel
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.util.mockito.argumentCaptor
@@ -43,6 +45,7 @@
@Mock private lateinit var statusBarStateController: StatusBarStateController
@Mock private lateinit var dozeHost: DozeHost
@Mock private lateinit var keyguardStateController: KeyguardStateController
+ @Mock private lateinit var wakefulnessLifecycle: WakefulnessLifecycle
private lateinit var underTest: KeyguardRepositoryImpl
@@ -55,6 +58,7 @@
statusBarStateController,
keyguardStateController,
dozeHost,
+ wakefulnessLifecycle,
)
}
@@ -184,4 +188,33 @@
job.cancel()
verify(statusBarStateController).removeCallback(captor.value)
}
+
+ @Test
+ fun wakefullness() = runBlockingTest {
+ val values = mutableListOf<WakefulnessModel>()
+ val job = underTest.wakefulnessState.onEach(values::add).launchIn(this)
+
+ val captor = argumentCaptor<WakefulnessLifecycle.Observer>()
+ verify(wakefulnessLifecycle).addObserver(captor.capture())
+
+ captor.value.onStartedWakingUp()
+ captor.value.onFinishedWakingUp()
+ captor.value.onStartedGoingToSleep()
+ captor.value.onFinishedGoingToSleep()
+
+ assertThat(values)
+ .isEqualTo(
+ listOf(
+ // Initial value will be ASLEEP
+ WakefulnessModel.ASLEEP,
+ WakefulnessModel.STARTING_TO_WAKE,
+ WakefulnessModel.AWAKE,
+ WakefulnessModel.STARTING_TO_SLEEP,
+ WakefulnessModel.ASLEEP,
+ )
+ )
+
+ job.cancel()
+ verify(wakefulnessLifecycle).removeObserver(captor.value)
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepositoryTest.kt
index 1b34100..64913c7c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepositoryTest.kt
@@ -63,7 +63,7 @@
@Before
fun setUp() {
- underTest = KeyguardTransitionRepository()
+ underTest = KeyguardTransitionRepositoryImpl()
wtfHandler = WtfHandler()
oldWtfHandler = Log.setWtfHandler(wtfHandler)
}
@@ -174,9 +174,6 @@
}
private fun assertSteps(steps: List<TransitionStep>, fractions: List<BigDecimal>) {
- // + 2 accounts for start and finish of automated transition
- assertThat(steps.size).isEqualTo(fractions.size + 2)
-
assertThat(steps[0]).isEqualTo(TransitionStep(AOD, LOCKSCREEN, 0f, TransitionState.STARTED))
fractions.forEachIndexed { index, fraction ->
assertThat(steps[index + 1])
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTest.kt
new file mode 100644
index 0000000..0424c28
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractorTest.kt
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.keyguard.domain.interactor
+
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.shared.model.KeyguardState.AOD
+import com.android.systemui.keyguard.shared.model.KeyguardState.GONE
+import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN
+import com.android.systemui.keyguard.shared.model.TransitionState.FINISHED
+import com.android.systemui.keyguard.shared.model.TransitionState.RUNNING
+import com.android.systemui.keyguard.shared.model.TransitionState.STARTED
+import com.android.systemui.keyguard.shared.model.TransitionStep
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.runBlocking
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@SmallTest
+@RunWith(JUnit4::class)
+class KeyguardTransitionInteractorTest : SysuiTestCase() {
+
+ private lateinit var underTest: KeyguardTransitionInteractor
+ private lateinit var repository: FakeKeyguardTransitionRepository
+
+ @Before
+ fun setUp() {
+ repository = FakeKeyguardTransitionRepository()
+ underTest = KeyguardTransitionInteractor(repository)
+ }
+
+ @Test
+ fun `transition collectors receives only appropriate events`() =
+ runBlocking(IMMEDIATE) {
+ var goneToAodSteps = mutableListOf<TransitionStep>()
+ val job1 =
+ underTest.goneToAodTransition.onEach { goneToAodSteps.add(it) }.launchIn(this)
+
+ var aodToLockscreenSteps = mutableListOf<TransitionStep>()
+ val job2 =
+ underTest.aodToLockscreenTransition
+ .onEach { aodToLockscreenSteps.add(it) }
+ .launchIn(this)
+
+ val steps = mutableListOf<TransitionStep>()
+ steps.add(TransitionStep(AOD, GONE, 0f, STARTED))
+ steps.add(TransitionStep(AOD, GONE, 1f, FINISHED))
+ steps.add(TransitionStep(AOD, LOCKSCREEN, 0f, STARTED))
+ steps.add(TransitionStep(AOD, LOCKSCREEN, 0.5f, RUNNING))
+ steps.add(TransitionStep(AOD, LOCKSCREEN, 1f, FINISHED))
+ steps.add(TransitionStep(GONE, AOD, 0f, STARTED))
+ steps.add(TransitionStep(GONE, AOD, 0.1f, RUNNING))
+ steps.add(TransitionStep(GONE, AOD, 0.2f, RUNNING))
+
+ steps.forEach { repository.sendTransitionStep(it) }
+
+ assertThat(aodToLockscreenSteps).isEqualTo(steps.subList(2, 5))
+ assertThat(goneToAodSteps).isEqualTo(steps.subList(5, 8))
+
+ job1.cancel()
+ job2.cancel()
+ }
+
+ @Test
+ fun dozeAmountTransitionTest() =
+ runBlocking(IMMEDIATE) {
+ var dozeAmountSteps = mutableListOf<TransitionStep>()
+ val job =
+ underTest.dozeAmountTransition.onEach { dozeAmountSteps.add(it) }.launchIn(this)
+
+ val steps = mutableListOf<TransitionStep>()
+
+ steps.add(TransitionStep(AOD, LOCKSCREEN, 0f, STARTED))
+ steps.add(TransitionStep(AOD, LOCKSCREEN, 0.5f, RUNNING))
+ steps.add(TransitionStep(AOD, LOCKSCREEN, 1f, FINISHED))
+ steps.add(TransitionStep(LOCKSCREEN, AOD, 0f, STARTED))
+ steps.add(TransitionStep(LOCKSCREEN, AOD, 0.8f, RUNNING))
+ steps.add(TransitionStep(LOCKSCREEN, AOD, 0.9f, RUNNING))
+ steps.add(TransitionStep(LOCKSCREEN, AOD, 1f, FINISHED))
+
+ steps.forEach { repository.sendTransitionStep(it) }
+
+ assertThat(dozeAmountSteps.subList(0, 3))
+ .isEqualTo(
+ listOf(
+ steps[0].copy(value = 1f - steps[0].value),
+ steps[1].copy(value = 1f - steps[1].value),
+ steps[2].copy(value = 1f - steps[2].value),
+ )
+ )
+ assertThat(dozeAmountSteps.subList(3, 7)).isEqualTo(steps.subList(3, 7))
+
+ job.cancel()
+ }
+
+ @Test
+ fun keyguardStateTests() =
+ runBlocking(IMMEDIATE) {
+ var finishedSteps = mutableListOf<KeyguardState>()
+ val job1 =
+ underTest.finishedKeyguardState.onEach { finishedSteps.add(it) }.launchIn(this)
+ var startedSteps = mutableListOf<KeyguardState>()
+ val job2 = underTest.startedKeyguardState.onEach { startedSteps.add(it) }.launchIn(this)
+
+ val steps = mutableListOf<TransitionStep>()
+
+ steps.add(TransitionStep(AOD, LOCKSCREEN, 0f, STARTED))
+ steps.add(TransitionStep(AOD, LOCKSCREEN, 0.5f, RUNNING))
+ steps.add(TransitionStep(AOD, LOCKSCREEN, 1f, FINISHED))
+ steps.add(TransitionStep(LOCKSCREEN, AOD, 0f, STARTED))
+ steps.add(TransitionStep(LOCKSCREEN, AOD, 0.9f, RUNNING))
+ steps.add(TransitionStep(LOCKSCREEN, AOD, 1f, FINISHED))
+ steps.add(TransitionStep(AOD, GONE, 1f, STARTED))
+
+ steps.forEach { repository.sendTransitionStep(it) }
+
+ assertThat(finishedSteps).isEqualTo(listOf(LOCKSCREEN, AOD))
+ assertThat(startedSteps).isEqualTo(listOf(LOCKSCREEN, AOD, GONE))
+
+ job1.cancel()
+ job2.cancel()
+ }
+
+ companion object {
+ private val IMMEDIATE = Dispatchers.Main.immediate
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/ColorSchemeTransitionTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/ColorSchemeTransitionTest.kt
index 5bb74e5..a8f4138 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/ColorSchemeTransitionTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/ColorSchemeTransitionTest.kt
@@ -25,6 +25,7 @@
import com.android.systemui.media.controls.models.GutsViewHolder
import com.android.systemui.media.controls.models.player.MediaViewHolder
import com.android.systemui.monet.ColorScheme
+import com.android.systemui.ripple.MultiRippleController
import junit.framework.Assert.assertEquals
import org.junit.After
import org.junit.Before
@@ -60,6 +61,7 @@
private lateinit var animatingColorTransitionFactory: AnimatingColorTransitionFactory
@Mock private lateinit var mediaViewHolder: MediaViewHolder
@Mock private lateinit var gutsViewHolder: GutsViewHolder
+ @Mock private lateinit var multiRippleController: MultiRippleController
@JvmField @Rule val mockitoRule = MockitoJUnit.rule()
@@ -70,7 +72,12 @@
whenever(extractColor.invoke(colorScheme)).thenReturn(TARGET_COLOR)
colorSchemeTransition =
- ColorSchemeTransition(context, mediaViewHolder, animatingColorTransitionFactory)
+ ColorSchemeTransition(
+ context,
+ mediaViewHolder,
+ multiRippleController,
+ animatingColorTransitionFactory
+ )
colorTransition =
object : AnimatingColorTransition(DEFAULT_COLOR, extractColor, applyColor) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaControlPanelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaControlPanelTest.kt
index 5843053..8190156 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaControlPanelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaControlPanelTest.kt
@@ -59,6 +59,8 @@
import com.android.systemui.SysuiTestCase
import com.android.systemui.bluetooth.BroadcastDialogController
import com.android.systemui.broadcast.BroadcastSender
+import com.android.systemui.flags.FakeFeatureFlags
+import com.android.systemui.flags.Flags
import com.android.systemui.media.controls.MediaTestUtils
import com.android.systemui.media.controls.models.GutsViewHolder
import com.android.systemui.media.controls.models.player.MediaAction
@@ -76,6 +78,7 @@
import com.android.systemui.media.dialog.MediaOutputDialogFactory
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.plugins.FalsingManager
+import com.android.systemui.ripple.MultiRippleView
import com.android.systemui.statusbar.NotificationLockscreenUserManager
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.util.animation.TransitionLayout
@@ -174,6 +177,7 @@
private lateinit var cancelText: TextView
private lateinit var dismiss: FrameLayout
private lateinit var dismissText: TextView
+ private lateinit var multiRippleView: MultiRippleView
private lateinit var session: MediaSession
private lateinit var device: MediaDeviceData
@@ -205,6 +209,8 @@
private lateinit var recSubtitle2: TextView
private lateinit var recSubtitle3: TextView
private var shouldShowBroadcastButton: Boolean = false
+ private val fakeFeatureFlag =
+ FakeFeatureFlags().apply { this.set(Flags.UMO_SURFACE_RIPPLE, false) }
@JvmField @Rule val mockito = MockitoJUnit.rule()
@@ -244,7 +250,8 @@
keyguardStateController,
activityIntentHelper,
lockscreenUserManager,
- broadcastDialogController
+ broadcastDialogController,
+ fakeFeatureFlag
) {
override fun loadAnimator(
animId: Int,
@@ -374,6 +381,8 @@
)
}
+ multiRippleView = MultiRippleView(context, null)
+
whenever(viewHolder.player).thenReturn(view)
whenever(viewHolder.appIcon).thenReturn(appIcon)
whenever(viewHolder.albumView).thenReturn(albumView)
@@ -414,6 +423,8 @@
whenever(viewHolder.getAction(R.id.action4)).thenReturn(action4)
whenever(viewHolder.actionsTopBarrier).thenReturn(actionsTopBarrier)
+
+ whenever(viewHolder.multiRippleView).thenReturn(multiRippleView)
}
/** Initialize elements for the recommendation view holder */
@@ -1973,6 +1984,50 @@
assertThat(expandedSet.getVisibility(recSubtitle3.id)).isEqualTo(ConstraintSet.GONE)
}
+ @Test
+ fun onButtonClick_touchRippleFlagEnabled_playsTouchRipple() {
+ fakeFeatureFlag.set(Flags.UMO_SURFACE_RIPPLE, true)
+ val semanticActions =
+ MediaButton(
+ playOrPause =
+ MediaAction(
+ icon = null,
+ action = {},
+ contentDescription = "play",
+ background = null
+ )
+ )
+ val data = mediaData.copy(semanticActions = semanticActions)
+ player.attachPlayer(viewHolder)
+ player.bindPlayer(data, KEY)
+
+ viewHolder.actionPlayPause.callOnClick()
+
+ assertThat(viewHolder.multiRippleView.ripples.size).isEqualTo(1)
+ }
+
+ @Test
+ fun onButtonClick_touchRippleFlagDisabled_doesNotPlayTouchRipple() {
+ fakeFeatureFlag.set(Flags.UMO_SURFACE_RIPPLE, false)
+ val semanticActions =
+ MediaButton(
+ playOrPause =
+ MediaAction(
+ icon = null,
+ action = {},
+ contentDescription = "play",
+ background = null
+ )
+ )
+ val data = mediaData.copy(semanticActions = semanticActions)
+ player.attachPlayer(viewHolder)
+ player.bindPlayer(data, KEY)
+
+ viewHolder.actionPlayPause.callOnClick()
+
+ assertThat(viewHolder.multiRippleView.ripples.size).isEqualTo(0)
+ }
+
private fun getScrubbingChangeListener(): SeekBarViewModel.ScrubbingChangeListener =
withArgCaptor {
verify(seekBarViewModel).setScrubbingChangeListener(capture())
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/carrier/QSCarrierTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/carrier/QSCarrierTest.java
index 99a17a6..9115ab3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/carrier/QSCarrierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/carrier/QSCarrierTest.java
@@ -24,6 +24,7 @@
import android.testing.TestableLooper;
import android.view.LayoutInflater;
import android.view.View;
+import android.widget.TextView;
import androidx.test.filters.SmallTest;
@@ -48,6 +49,7 @@
public void setUp() throws Exception {
mTestableLooper = TestableLooper.get(this);
LayoutInflater inflater = LayoutInflater.from(mContext);
+ mContext.ensureTestableResources();
mTestableLooper.runWithLooper(() ->
mQSCarrier = (QSCarrier) inflater.inflate(R.layout.qs_carrier, null));
@@ -119,4 +121,30 @@
mQSCarrier.updateState(c, true);
assertEquals(View.GONE, mQSCarrier.getRSSIView().getVisibility());
}
+
+ @Test
+ public void testCarrierNameMaxWidth_smallScreen_fromResource() {
+ int maxEms = 10;
+ mContext.getOrCreateTestableResources().addOverride(R.integer.qs_carrier_max_em, maxEms);
+ mContext.getOrCreateTestableResources()
+ .addOverride(R.bool.config_use_large_screen_shade_header, false);
+ TextView carrierText = mQSCarrier.requireViewById(R.id.qs_carrier_text);
+
+ mQSCarrier.onConfigurationChanged(mContext.getResources().getConfiguration());
+
+ assertEquals(maxEms, carrierText.getMaxEms());
+ }
+
+ @Test
+ public void testCarrierNameMaxWidth_largeScreen_maxInt() {
+ int maxEms = 10;
+ mContext.getOrCreateTestableResources().addOverride(R.integer.qs_carrier_max_em, maxEms);
+ mContext.getOrCreateTestableResources()
+ .addOverride(R.bool.config_use_large_screen_shade_header, true);
+ TextView carrierText = mQSCarrier.requireViewById(R.id.qs_carrier_text);
+
+ mQSCarrier.onConfigurationChanged(mContext.getResources().getConfiguration());
+
+ assertEquals(Integer.MAX_VALUE, carrierText.getMaxEms());
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/ripple/MultiRippleControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/ripple/MultiRippleControllerTest.kt
new file mode 100644
index 0000000..05512e5
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/ripple/MultiRippleControllerTest.kt
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.ripple
+
+import android.graphics.Color
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.ripple.MultiRippleController.Companion.MAX_RIPPLE_NUMBER
+import com.android.systemui.util.concurrency.FakeExecutor
+import com.android.systemui.util.time.FakeSystemClock
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class MultiRippleControllerTest : SysuiTestCase() {
+ private lateinit var multiRippleController: MultiRippleController
+ private lateinit var multiRippleView: MultiRippleView
+ private lateinit var rippleAnimationConfig: RippleAnimationConfig
+ private val fakeSystemClock = FakeSystemClock()
+
+ // FakeExecutor is needed to run animator.
+ private val fakeExecutor = FakeExecutor(fakeSystemClock)
+
+ @Before
+ fun setup() {
+ rippleAnimationConfig = RippleAnimationConfig(duration = 1000L)
+ multiRippleView = MultiRippleView(context, null)
+ multiRippleController = MultiRippleController(multiRippleView)
+ }
+
+ @Test
+ fun updateColor_updatesColor() {
+ val initialColor = Color.WHITE
+ val expectedColor = Color.RED
+
+ fakeExecutor.execute {
+ val rippleAnimation =
+ RippleAnimation(rippleAnimationConfig.apply { this.color = initialColor })
+
+ with(multiRippleController) {
+ play(rippleAnimation)
+ updateColor(expectedColor)
+ }
+
+ assertThat(rippleAnimationConfig.color).isEqualTo(expectedColor)
+ }
+ }
+
+ @Test
+ fun play_playsRipple() {
+ fakeExecutor.execute {
+ val rippleAnimation = RippleAnimation(rippleAnimationConfig)
+
+ multiRippleController.play(rippleAnimation)
+
+ assertThat(multiRippleView.ripples.size).isEqualTo(1)
+ assertThat(multiRippleView.ripples[0]).isEqualTo(rippleAnimation)
+ }
+ }
+
+ @Test
+ fun play_doesNotExceedMaxRipple() {
+ fakeExecutor.execute {
+ for (i in 0..MAX_RIPPLE_NUMBER + 10) {
+ multiRippleController.play(RippleAnimation(rippleAnimationConfig))
+ }
+
+ assertThat(multiRippleView.ripples.size).isEqualTo(MAX_RIPPLE_NUMBER)
+ }
+ }
+
+ @Test
+ fun play_onEnd_removesAnimation() {
+ fakeExecutor.execute {
+ val rippleAnimation = RippleAnimation(rippleAnimationConfig)
+ multiRippleController.play(rippleAnimation)
+
+ assertThat(multiRippleView.ripples.size).isEqualTo(1)
+ assertThat(multiRippleView.ripples[0]).isEqualTo(rippleAnimation)
+
+ fakeSystemClock.advanceTime(rippleAnimationConfig.duration)
+
+ assertThat(multiRippleView.ripples.size).isEqualTo(0)
+ }
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/ripple/RippleAnimationTest.kt b/packages/SystemUI/tests/src/com/android/systemui/ripple/RippleAnimationTest.kt
new file mode 100644
index 0000000..7662282
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/ripple/RippleAnimationTest.kt
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.ripple
+
+import android.graphics.Color
+import android.testing.AndroidTestingRunner
+import androidx.core.graphics.ColorUtils
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.util.concurrency.FakeExecutor
+import com.android.systemui.util.time.FakeSystemClock
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class RippleAnimationTest : SysuiTestCase() {
+
+ private val fakeSystemClock = FakeSystemClock()
+ private val fakeExecutor = FakeExecutor(fakeSystemClock)
+
+ @Test
+ fun init_shaderHasCorrectConfig() {
+ val config =
+ RippleAnimationConfig(
+ duration = 3000L,
+ pixelDensity = 2f,
+ color = Color.RED,
+ opacity = 30,
+ shouldFillRipple = true,
+ sparkleStrength = 0.3f
+ )
+ val rippleAnimation = RippleAnimation(config)
+
+ with(rippleAnimation.rippleShader) {
+ assertThat(rippleFill).isEqualTo(config.shouldFillRipple)
+ assertThat(pixelDensity).isEqualTo(config.pixelDensity)
+ assertThat(color).isEqualTo(ColorUtils.setAlphaComponent(config.color, config.opacity))
+ assertThat(sparkleStrength).isEqualTo(config.sparkleStrength)
+ }
+ }
+
+ @Test
+ fun updateColor_updatesColorCorrectly() {
+ val initialColor = Color.WHITE
+ val expectedColor = Color.RED
+ val config = RippleAnimationConfig(color = initialColor)
+ val rippleAnimation = RippleAnimation(config)
+
+ fakeExecutor.execute {
+ with(rippleAnimation) {
+ play()
+ updateColor(expectedColor)
+ }
+
+ assertThat(config.color).isEqualTo(expectedColor)
+ }
+ }
+
+ @Test
+ fun play_updatesIsPlaying() {
+ val config = RippleAnimationConfig(duration = 1000L)
+ val rippleAnimation = RippleAnimation(config)
+
+ fakeExecutor.execute {
+ rippleAnimation.play()
+
+ assertThat(rippleAnimation.isPlaying()).isTrue()
+
+ // move time to finish the animation
+ fakeSystemClock.advanceTime(config.duration)
+
+ assertThat(rippleAnimation.isPlaying()).isFalse()
+ }
+ }
+
+ @Test
+ fun play_onEnd_triggersOnAnimationEnd() {
+ val config = RippleAnimationConfig(duration = 1000L)
+ val rippleAnimation = RippleAnimation(config)
+ var animationEnd = false
+
+ fakeExecutor.execute {
+ rippleAnimation.play(onAnimationEnd = { animationEnd = true })
+
+ fakeSystemClock.advanceTime(config.duration)
+
+ assertThat(animationEnd).isTrue()
+ }
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ImageExporterTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ImageExporterTest.java
index 4c44dac..f4bc232 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ImageExporterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ImageExporterTest.java
@@ -23,6 +23,7 @@
import static java.nio.charset.StandardCharsets.US_ASCII;
+import android.content.ContentProvider;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.graphics.Bitmap;
@@ -31,9 +32,11 @@
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
+import android.net.Uri;
import android.os.Build;
import android.os.ParcelFileDescriptor;
import android.os.Process;
+import android.os.UserHandle;
import android.provider.MediaStore;
import android.testing.AndroidTestingRunner;
@@ -41,11 +44,18 @@
import androidx.test.filters.MediumTest;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.flags.FakeFeatureFlags;
+import com.android.systemui.flags.Flags;
import com.google.common.util.concurrent.ListenableFuture;
+import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
import java.io.ByteArrayInputStream;
import java.io.IOException;
@@ -60,7 +70,6 @@
@RunWith(AndroidTestingRunner.class)
@MediumTest // file I/O
public class ImageExporterTest extends SysuiTestCase {
-
/** Executes directly in the caller's thread */
private static final Executor DIRECT_EXECUTOR = Runnable::run;
private static final byte[] EXIF_FILE_TAG = "Exif\u0000\u0000".getBytes(US_ASCII);
@@ -68,6 +77,15 @@
private static final ZonedDateTime CAPTURE_TIME =
ZonedDateTime.of(LocalDateTime.of(2020, 12, 15, 13, 15), ZoneId.of("EST"));
+ private FakeFeatureFlags mFeatureFlags = new FakeFeatureFlags();
+ @Mock
+ private ContentResolver mMockContentResolver;
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+ }
+
@Test
public void testImageFilename() {
assertEquals("image file name", "Screenshot_20201215-131500.png",
@@ -92,7 +110,8 @@
@Test
public void testImageExport() throws ExecutionException, InterruptedException, IOException {
ContentResolver contentResolver = mContext.getContentResolver();
- ImageExporter exporter = new ImageExporter(contentResolver);
+ mFeatureFlags.set(Flags.SCREENSHOT_WORK_PROFILE_POLICY, true);
+ ImageExporter exporter = new ImageExporter(contentResolver, mFeatureFlags);
UUID requestId = UUID.fromString("3c11da99-9284-4863-b1d5-6f3684976814");
Bitmap original = createCheckerBitmap(10, 10, 10);
@@ -168,6 +187,44 @@
values.getAsLong(MediaStore.MediaColumns.DATE_EXPIRES));
}
+ @Test
+ public void testSetUser() {
+ mFeatureFlags.set(Flags.SCREENSHOT_WORK_PROFILE_POLICY, true);
+ ImageExporter exporter = new ImageExporter(mMockContentResolver, mFeatureFlags);
+
+ UserHandle imageUserHande = UserHandle.of(10);
+
+ ArgumentCaptor<Uri> uriCaptor = ArgumentCaptor.forClass(Uri.class);
+ // Capture the URI and then return null to bail out of export.
+ Mockito.when(mMockContentResolver.insert(uriCaptor.capture(), Mockito.any())).thenReturn(
+ null);
+ exporter.export(DIRECT_EXECUTOR, UUID.fromString("3c11da99-9284-4863-b1d5-6f3684976814"),
+ null, CAPTURE_TIME, imageUserHande);
+
+ Uri expected = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
+ expected = ContentProvider.maybeAddUserId(expected, imageUserHande.getIdentifier());
+
+ assertEquals(expected, uriCaptor.getValue());
+ }
+
+ @Test
+ public void testSetUser_noWorkProfile() {
+ mFeatureFlags.set(Flags.SCREENSHOT_WORK_PROFILE_POLICY, false);
+ ImageExporter exporter = new ImageExporter(mMockContentResolver, mFeatureFlags);
+
+ UserHandle imageUserHandle = UserHandle.of(10);
+
+ ArgumentCaptor<Uri> uriCaptor = ArgumentCaptor.forClass(Uri.class);
+ // Capture the URI and then return null to bail out of export.
+ Mockito.when(mMockContentResolver.insert(uriCaptor.capture(), Mockito.any())).thenReturn(
+ null);
+ exporter.export(DIRECT_EXECUTOR, UUID.fromString("3c11da99-9284-4863-b1d5-6f3684976814"),
+ null, CAPTURE_TIME, imageUserHandle);
+
+ // The user handle should be ignored here since the flag is off.
+ assertEquals(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, uriCaptor.getValue());
+ }
+
@SuppressWarnings("SameParameterValue")
private Bitmap createCheckerBitmap(int tileSize, int w, int h) {
Bitmap bitmap = Bitmap.createBitmap(w * tileSize, h * tileSize, Bitmap.Config.ARGB_8888);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotServiceTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotServiceTest.kt
index 3a4da86..fa1fedb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotServiceTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotServiceTest.kt
@@ -62,7 +62,7 @@
import org.mockito.Mockito.`when` as whenever
private const val USER_ID = 1
-private const val TASK_ID = 1
+private const val TASK_ID = 11
@RunWith(AndroidTestingRunner::class)
@SmallTest
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
index ac4dd49..45b4353 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
@@ -129,7 +129,6 @@
import com.android.systemui.statusbar.StatusBarStateControllerImpl;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.VibratorHelper;
-import com.android.systemui.statusbar.events.PrivacyDotViewController;
import com.android.systemui.statusbar.notification.ConversationNotificationManager;
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
@@ -153,7 +152,6 @@
import com.android.systemui.statusbar.phone.KeyguardStatusBarView;
import com.android.systemui.statusbar.phone.KeyguardStatusBarViewController;
import com.android.systemui.statusbar.phone.LockscreenGestureLogger;
-import com.android.systemui.statusbar.phone.NotificationIconAreaController;
import com.android.systemui.statusbar.phone.ScreenOffAnimationController;
import com.android.systemui.statusbar.phone.ScrimController;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
@@ -199,7 +197,6 @@
@Mock private KeyguardBottomAreaView mKeyguardBottomArea;
@Mock private KeyguardBottomAreaViewController mKeyguardBottomAreaViewController;
@Mock private KeyguardBottomAreaView mQsFrame;
- @Mock private NotificationIconAreaController mNotificationAreaController;
@Mock private HeadsUpManagerPhone mHeadsUpManager;
@Mock private NotificationShelfController mNotificationShelfController;
@Mock private KeyguardStatusBarView mKeyguardStatusBar;
@@ -227,7 +224,7 @@
@Mock private Resources mResources;
@Mock private Configuration mConfiguration;
@Mock private KeyguardClockSwitch mKeyguardClockSwitch;
- @Mock private MediaHierarchyManager mMediaHiearchyManager;
+ @Mock private MediaHierarchyManager mMediaHierarchyManager;
@Mock private ConversationNotificationManager mConversationNotificationManager;
@Mock private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
@Mock private KeyguardStatusViewComponent.Factory mKeyguardStatusViewComponentFactory;
@@ -254,7 +251,6 @@
@Mock private UiEventLogger mUiEventLogger;
@Mock private LockIconViewController mLockIconViewController;
@Mock private KeyguardMediaController mKeyguardMediaController;
- @Mock private PrivacyDotViewController mPrivacyDotViewController;
@Mock private NavigationModeController mNavigationModeController;
@Mock private NavigationBarController mNavigationBarController;
@Mock private LargeScreenShadeHeaderController mLargeScreenShadeHeaderController;
@@ -294,7 +290,7 @@
private ConfigurationController mConfigurationController;
private SysuiStatusBarStateController mStatusBarStateController;
private NotificationPanelViewController mNotificationPanelViewController;
- private View.AccessibilityDelegate mAccessibiltyDelegate;
+ private View.AccessibilityDelegate mAccessibilityDelegate;
private NotificationsQuickSettingsContainer mNotificationContainerParent;
private List<View.OnAttachStateChangeListener> mOnAttachStateChangeListeners;
private Handler mMainHandler;
@@ -456,7 +452,7 @@
mShadeLog,
mConfigurationController,
() -> flingAnimationUtilsBuilder, mStatusBarTouchableRegionManager,
- mConversationNotificationManager, mMediaHiearchyManager,
+ mConversationNotificationManager, mMediaHierarchyManager,
mStatusBarKeyguardViewManager,
mNotificationsQSContainerController,
mNotificationStackScrollLayoutController,
@@ -465,7 +461,6 @@
mKeyguardUserSwitcherComponentFactory,
mKeyguardStatusBarViewComponentFactory,
mLockscreenShadeTransitionController,
- mNotificationAreaController,
mAuthController,
mScrimController,
mUserManager,
@@ -474,7 +469,6 @@
mAmbientState,
mLockIconViewController,
mKeyguardMediaController,
- mPrivacyDotViewController,
mTapAgainViewController,
mNavigationModeController,
mNavigationBarController,
@@ -516,9 +510,9 @@
ArgumentCaptor<View.AccessibilityDelegate> accessibilityDelegateArgumentCaptor =
ArgumentCaptor.forClass(View.AccessibilityDelegate.class);
verify(mView).setAccessibilityDelegate(accessibilityDelegateArgumentCaptor.capture());
- mAccessibiltyDelegate = accessibilityDelegateArgumentCaptor.getValue();
+ mAccessibilityDelegate = accessibilityDelegateArgumentCaptor.getValue();
mNotificationPanelViewController.getStatusBarStateController()
- .addCallback(mNotificationPanelViewController.mStatusBarStateListener);
+ .addCallback(mNotificationPanelViewController.getStatusBarStateListener());
mNotificationPanelViewController
.setHeadsUpAppearanceController(mock(HeadsUpAppearanceController.class));
verify(mNotificationStackScrollLayoutController)
@@ -773,8 +767,8 @@
0L /* eventTime */, MotionEvent.ACTION_UP, 0f /* x */, 300f /* y */,
0 /* metaState */));
- assertThat(mNotificationPanelViewController.getClosing()).isTrue();
- assertThat(mNotificationPanelViewController.getIsFlinging()).isTrue();
+ assertThat(mNotificationPanelViewController.isClosing()).isTrue();
+ assertThat(mNotificationPanelViewController.isFlinging()).isTrue();
// simulate touch that does not exceed touch slop
onTouchEvent(MotionEvent.obtain(2L /* downTime */,
@@ -788,8 +782,8 @@
0 /* metaState */));
// fling should still be called after a touch that does not exceed touch slop
- assertThat(mNotificationPanelViewController.getClosing()).isTrue();
- assertThat(mNotificationPanelViewController.getIsFlinging()).isTrue();
+ assertThat(mNotificationPanelViewController.isClosing()).isTrue();
+ assertThat(mNotificationPanelViewController.isFlinging()).isTrue();
}
@Test
@@ -844,7 +838,7 @@
@Test
public void testA11y_initializeNode() {
AccessibilityNodeInfo nodeInfo = new AccessibilityNodeInfo();
- mAccessibiltyDelegate.onInitializeAccessibilityNodeInfo(mView, nodeInfo);
+ mAccessibilityDelegate.onInitializeAccessibilityNodeInfo(mView, nodeInfo);
List<AccessibilityNodeInfo.AccessibilityAction> actionList = nodeInfo.getActionList();
assertThat(actionList).containsAtLeastElementsIn(
@@ -856,7 +850,7 @@
@Test
public void testA11y_scrollForward() {
- mAccessibiltyDelegate.performAccessibilityAction(
+ mAccessibilityDelegate.performAccessibilityAction(
mView,
AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_FORWARD.getId(),
null);
@@ -866,7 +860,7 @@
@Test
public void testA11y_scrollUp() {
- mAccessibiltyDelegate.performAccessibilityAction(
+ mAccessibilityDelegate.performAccessibilityAction(
mView,
AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_UP.getId(),
null);
@@ -1282,7 +1276,7 @@
mNotificationPanelViewController.expandWithQs();
verify(mLockscreenShadeTransitionController).goToLockedShade(
- /* expandedView= */null, /* needsQSAnimation= */false);
+ /* expandedView= */null, /* needsQSAnimation= */true);
}
@Test
@@ -1329,11 +1323,11 @@
public void testQsToBeImmediatelyExpandedWhenOpeningPanelInSplitShade() {
enableSplitShade(/* enabled= */ true);
mShadeExpansionStateManager.updateState(STATE_CLOSED);
- assertThat(mNotificationPanelViewController.mQsExpandImmediate).isFalse();
+ assertThat(mNotificationPanelViewController.isQsExpandImmediate()).isFalse();
mShadeExpansionStateManager.updateState(STATE_OPENING);
- assertThat(mNotificationPanelViewController.mQsExpandImmediate).isTrue();
+ assertThat(mNotificationPanelViewController.isQsExpandImmediate()).isTrue();
}
@Test
@@ -1345,18 +1339,18 @@
// going to lockscreen would trigger STATE_OPENING
mShadeExpansionStateManager.updateState(STATE_OPENING);
- assertThat(mNotificationPanelViewController.mQsExpandImmediate).isFalse();
+ assertThat(mNotificationPanelViewController.isQsExpandImmediate()).isFalse();
}
@Test
public void testQsImmediateResetsWhenPanelOpensOrCloses() {
- mNotificationPanelViewController.mQsExpandImmediate = true;
+ mNotificationPanelViewController.setQsExpandImmediate(true);
mShadeExpansionStateManager.updateState(STATE_OPEN);
- assertThat(mNotificationPanelViewController.mQsExpandImmediate).isFalse();
+ assertThat(mNotificationPanelViewController.isQsExpandImmediate()).isFalse();
- mNotificationPanelViewController.mQsExpandImmediate = true;
+ mNotificationPanelViewController.setQsExpandImmediate(true);
mShadeExpansionStateManager.updateState(STATE_CLOSED);
- assertThat(mNotificationPanelViewController.mQsExpandImmediate).isFalse();
+ assertThat(mNotificationPanelViewController.isQsExpandImmediate()).isFalse();
}
@Test
@@ -1399,7 +1393,7 @@
@Test
public void interceptTouchEvent_withinQs_shadeExpanded_startsQsTracking() {
- mNotificationPanelViewController.mQs = mQs;
+ mNotificationPanelViewController.setQs(mQs);
when(mQsFrame.getX()).thenReturn(0f);
when(mQsFrame.getWidth()).thenReturn(1000);
when(mQsHeader.getTop()).thenReturn(0);
@@ -1419,7 +1413,7 @@
@Test
public void interceptTouchEvent_withinQs_shadeExpanded_inSplitShade_doesNotStartQsTracking() {
enableSplitShade(true);
- mNotificationPanelViewController.mQs = mQs;
+ mNotificationPanelViewController.setQs(mQs);
when(mQsFrame.getX()).thenReturn(0f);
when(mQsFrame.getWidth()).thenReturn(1000);
when(mQsHeader.getTop()).thenReturn(0);
@@ -1495,7 +1489,7 @@
@Test
public void onLayoutChange_fullWidth_updatesQSWithFullWithTrue() {
- mNotificationPanelViewController.mQs = mQs;
+ mNotificationPanelViewController.setQs(mQs);
setIsFullWidth(true);
@@ -1504,7 +1498,7 @@
@Test
public void onLayoutChange_notFullWidth_updatesQSWithFullWithFalse() {
- mNotificationPanelViewController.mQs = mQs;
+ mNotificationPanelViewController.setQs(mQs);
setIsFullWidth(false);
@@ -1513,7 +1507,7 @@
@Test
public void onLayoutChange_qsNotSet_doesNotCrash() {
- mNotificationPanelViewController.mQs = null;
+ mNotificationPanelViewController.setQs(null);
triggerLayoutChange();
}
@@ -1539,7 +1533,7 @@
@Test
public void setQsExpansion_lockscreenShadeTransitionInProgress_usesLockscreenSquishiness() {
float squishinessFraction = 0.456f;
- mNotificationPanelViewController.mQs = mQs;
+ mNotificationPanelViewController.setQs(mQs);
when(mLockscreenShadeTransitionController.getQsSquishTransitionFraction())
.thenReturn(squishinessFraction);
when(mNotificationStackScrollLayoutController.getNotificationSquishinessFraction())
@@ -1552,7 +1546,7 @@
/* delay= */ 0
);
- mNotificationPanelViewController.setQsExpansion(/* height= */ 123);
+ mNotificationPanelViewController.setQsExpansionHeight(/* height= */ 123);
// First for setTransitionToFullShadeAmount and then setQsExpansion
verify(mQs, times(2)).setQsExpansion(
@@ -1567,13 +1561,13 @@
public void setQsExpansion_lockscreenShadeTransitionNotInProgress_usesStandardSquishiness() {
float lsSquishinessFraction = 0.456f;
float nsslSquishinessFraction = 0.987f;
- mNotificationPanelViewController.mQs = mQs;
+ mNotificationPanelViewController.setQs(mQs);
when(mLockscreenShadeTransitionController.getQsSquishTransitionFraction())
.thenReturn(lsSquishinessFraction);
when(mNotificationStackScrollLayoutController.getNotificationSquishinessFraction())
.thenReturn(nsslSquishinessFraction);
- mNotificationPanelViewController.setQsExpansion(/* height= */ 123);
+ mNotificationPanelViewController.setQsExpansionHeight(/* height= */ 123);
verify(mQs).setQsExpansion(
/* expansion= */ anyFloat(),
@@ -1586,7 +1580,7 @@
@Test
public void onEmptySpaceClicked_notDozingAndOnKeyguard_requestsFaceAuth() {
StatusBarStateController.StateListener statusBarStateListener =
- mNotificationPanelViewController.mStatusBarStateListener;
+ mNotificationPanelViewController.getStatusBarStateListener();
statusBarStateListener.onStateChanged(KEYGUARD);
mNotificationPanelViewController.setDozing(false, false);
@@ -1601,7 +1595,7 @@
@Test
public void onEmptySpaceClicked_notDozingAndFaceDetectionIsNotRunning_startsUnlockAnimation() {
StatusBarStateController.StateListener statusBarStateListener =
- mNotificationPanelViewController.mStatusBarStateListener;
+ mNotificationPanelViewController.getStatusBarStateListener();
statusBarStateListener.onStateChanged(KEYGUARD);
mNotificationPanelViewController.setDozing(false, false);
when(mUpdateMonitor.requestFaceAuth(NOTIFICATION_PANEL_CLICKED)).thenReturn(false);
@@ -1616,7 +1610,7 @@
@Test
public void onEmptySpaceClicked_notDozingAndFaceDetectionIsRunning_doesNotStartUnlockHint() {
StatusBarStateController.StateListener statusBarStateListener =
- mNotificationPanelViewController.mStatusBarStateListener;
+ mNotificationPanelViewController.getStatusBarStateListener();
statusBarStateListener.onStateChanged(KEYGUARD);
mNotificationPanelViewController.setDozing(false, false);
when(mUpdateMonitor.requestFaceAuth(NOTIFICATION_PANEL_CLICKED)).thenReturn(true);
@@ -1631,7 +1625,7 @@
@Test
public void onEmptySpaceClicked_whenDozingAndOnKeyguard_doesNotRequestFaceAuth() {
StatusBarStateController.StateListener statusBarStateListener =
- mNotificationPanelViewController.mStatusBarStateListener;
+ mNotificationPanelViewController.getStatusBarStateListener();
statusBarStateListener.onStateChanged(KEYGUARD);
mNotificationPanelViewController.setDozing(true, false);
@@ -1645,7 +1639,7 @@
@Test
public void onEmptySpaceClicked_whenStatusBarShadeLocked_doesNotRequestFaceAuth() {
StatusBarStateController.StateListener statusBarStateListener =
- mNotificationPanelViewController.mStatusBarStateListener;
+ mNotificationPanelViewController.getStatusBarStateListener();
statusBarStateListener.onStateChanged(SHADE_LOCKED);
mEmptySpaceClickListenerCaptor.getValue().onEmptySpaceClicked(0, 0);
@@ -1664,11 +1658,11 @@
public void onShadeFlingClosingEnd_mAmbientStateSetClose_thenOnExpansionStopped() {
// Given: Shade is expanded
mNotificationPanelViewController.notifyExpandingFinished();
- mNotificationPanelViewController.setIsClosing(false);
+ mNotificationPanelViewController.setClosing(false);
// When: Shade flings to close not canceled
mNotificationPanelViewController.notifyExpandingStarted();
- mNotificationPanelViewController.setIsClosing(true);
+ mNotificationPanelViewController.setClosing(true);
mNotificationPanelViewController.onFlingEnd(false);
// Then: AmbientState's mIsClosing should be set to false
@@ -1680,6 +1674,15 @@
inOrder.verify(mNotificationStackScrollLayoutController).onExpansionStopped();
}
+ @Test
+ public void inUnlockedSplitShade_transitioningMaxTransitionDistance_makesShadeFullyExpanded() {
+ mStatusBarStateController.setState(SHADE);
+ enableSplitShade(true);
+ int transitionDistance = mNotificationPanelViewController.getMaxPanelTransitionDistance();
+ mNotificationPanelViewController.setExpandedHeight(transitionDistance);
+ assertThat(mNotificationPanelViewController.isFullyExpanded()).isTrue();
+ }
+
private static MotionEvent createMotionEvent(int x, int y, int action) {
return MotionEvent.obtain(
/* downTime= */ 0, /* eventTime= */ 0, action, x, y, /* metaState= */ 0);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/regionsampling/RegionSamplingInstanceTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shared/regionsampling/RegionSamplerTest.kt
similarity index 64%
rename from packages/SystemUI/tests/src/com/android/systemui/shared/regionsampling/RegionSamplingInstanceTest.kt
rename to packages/SystemUI/tests/src/com/android/systemui/shared/regionsampling/RegionSamplerTest.kt
index 09d51f6..5a62cc1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shared/regionsampling/RegionSamplingInstanceTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/regionsampling/RegionSamplerTest.kt
@@ -21,61 +21,55 @@
@RunWith(AndroidTestingRunner::class)
@SmallTest
-class RegionSamplingInstanceTest : SysuiTestCase() {
+class RegionSamplerTest : SysuiTestCase() {
- @JvmField @Rule
- val mockito = MockitoJUnit.rule()
+ @JvmField @Rule val mockito = MockitoJUnit.rule()
@Mock private lateinit var sampledView: View
@Mock private lateinit var mainExecutor: Executor
@Mock private lateinit var bgExecutor: Executor
@Mock private lateinit var regionSampler: RegionSamplingHelper
- @Mock private lateinit var updateFun: RegionSamplingInstance.UpdateColorCallback
@Mock private lateinit var pw: PrintWriter
@Mock private lateinit var callback: RegionSamplingHelper.SamplingCallback
- private lateinit var regionSamplingInstance: RegionSamplingInstance
+ private lateinit var mRegionSampler: RegionSampler
+ private var updateFun: UpdateColorCallback = {}
@Before
fun setUp() {
whenever(sampledView.isAttachedToWindow).thenReturn(true)
- whenever(regionSampler.callback).thenReturn(this@RegionSamplingInstanceTest.callback)
+ whenever(regionSampler.callback).thenReturn(this@RegionSamplerTest.callback)
- regionSamplingInstance = object : RegionSamplingInstance(
- sampledView,
- mainExecutor,
- bgExecutor,
- true,
- updateFun
- ) {
- override fun createRegionSamplingHelper(
+ mRegionSampler =
+ object : RegionSampler(sampledView, mainExecutor, bgExecutor, true, updateFun) {
+ override fun createRegionSamplingHelper(
sampledView: View,
callback: RegionSamplingHelper.SamplingCallback,
mainExecutor: Executor?,
bgExecutor: Executor?
- ): RegionSamplingHelper {
- return this@RegionSamplingInstanceTest.regionSampler
+ ): RegionSamplingHelper {
+ return this@RegionSamplerTest.regionSampler
+ }
}
- }
}
@Test
fun testStartRegionSampler() {
- regionSamplingInstance.startRegionSampler()
+ mRegionSampler.startRegionSampler()
verify(regionSampler).start(Rect(0, 0, 0, 0))
}
@Test
fun testStopRegionSampler() {
- regionSamplingInstance.stopRegionSampler()
+ mRegionSampler.stopRegionSampler()
verify(regionSampler).stop()
}
@Test
fun testDump() {
- regionSamplingInstance.dump(pw)
+ mRegionSampler.dump(pw)
verify(regionSampler).dump(pw)
}
@@ -91,23 +85,18 @@
@Test
fun testFlagFalse() {
- regionSamplingInstance = object : RegionSamplingInstance(
- sampledView,
- mainExecutor,
- bgExecutor,
- false,
- updateFun
- ) {
- override fun createRegionSamplingHelper(
+ mRegionSampler =
+ object : RegionSampler(sampledView, mainExecutor, bgExecutor, false, updateFun) {
+ override fun createRegionSamplingHelper(
sampledView: View,
callback: RegionSamplingHelper.SamplingCallback,
mainExecutor: Executor?,
bgExecutor: Executor?
- ): RegionSamplingHelper {
- return this@RegionSamplingInstanceTest.regionSampler
+ ): RegionSamplingHelper {
+ return this@RegionSamplerTest.regionSampler
+ }
}
- }
- Assert.assertEquals(regionSamplingInstance.regionSampler, null)
+ Assert.assertEquals(mRegionSampler.regionSampler, null)
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt
index 3ff7639..f96c39f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt
@@ -406,6 +406,10 @@
verify(mHeadsUpManager, never()).showNotification(mGroupSummary)
verify(mHeadsUpManager).showNotification(mGroupSibling1)
+
+ // In addition make sure we have explicitly marked the summary as having interrupted due
+ // to the alert being transferred
+ assertTrue(mGroupSummary.hasInterrupted())
}
@Test
@@ -424,6 +428,7 @@
verify(mHeadsUpManager, never()).showNotification(mGroupSummary)
verify(mHeadsUpManager).showNotification(mGroupChild1)
+ assertTrue(mGroupSummary.hasInterrupted())
}
@Test
@@ -449,6 +454,7 @@
verify(mHeadsUpManager, never()).showNotification(mGroupSummary)
verify(mHeadsUpManager).showNotification(mGroupSibling1)
verify(mHeadsUpManager, never()).showNotification(mGroupSibling2)
+ assertTrue(mGroupSummary.hasInterrupted())
}
@Test
@@ -474,6 +480,7 @@
verify(mHeadsUpManager, never()).showNotification(mGroupSummary)
verify(mHeadsUpManager).showNotification(mGroupChild1)
verify(mHeadsUpManager, never()).showNotification(mGroupChild2)
+ assertTrue(mGroupSummary.hasInterrupted())
}
@Test
@@ -512,6 +519,7 @@
verify(mHeadsUpManager).showNotification(mGroupPriority)
verify(mHeadsUpManager, never()).showNotification(mGroupSibling1)
verify(mHeadsUpManager, never()).showNotification(mGroupSibling2)
+ assertTrue(mGroupSummary.hasInterrupted())
}
@Test
@@ -548,6 +556,7 @@
verify(mHeadsUpManager).showNotification(mGroupPriority)
verify(mHeadsUpManager, never()).showNotification(mGroupSibling1)
verify(mHeadsUpManager, never()).showNotification(mGroupSibling2)
+ assertTrue(mGroupSummary.hasInterrupted())
}
@Test
@@ -582,6 +591,7 @@
verify(mHeadsUpManager).showNotification(mGroupPriority)
verify(mHeadsUpManager, never()).showNotification(mGroupSibling1)
verify(mHeadsUpManager, never()).showNotification(mGroupSibling2)
+ assertTrue(mGroupSummary.hasInterrupted())
}
@Test
@@ -672,6 +682,35 @@
}
@Test
+ fun testNoTransfer_groupSummaryNotAlerting() {
+ // When we have a group where the summary should not alert and exactly one child should
+ // alert, we should never mark the group summary as interrupted (because it doesn't).
+ setShouldHeadsUp(mGroupSummary, false)
+ setShouldHeadsUp(mGroupChild1, true)
+ setShouldHeadsUp(mGroupChild2, false)
+
+ mCollectionListener.onEntryAdded(mGroupSummary)
+ mCollectionListener.onEntryAdded(mGroupChild1)
+ mCollectionListener.onEntryAdded(mGroupChild2)
+ val groupEntry = GroupEntryBuilder()
+ .setSummary(mGroupSummary)
+ .setChildren(listOf(mGroupChild1, mGroupChild2))
+ .build()
+ mBeforeTransformGroupsListener.onBeforeTransformGroups(listOf(groupEntry))
+ verify(mHeadsUpViewBinder, never()).bindHeadsUpView(any(), any())
+ mBeforeFinalizeFilterListener.onBeforeFinalizeFilter(listOf(groupEntry))
+
+ verify(mHeadsUpViewBinder, never()).bindHeadsUpView(eq(mGroupSummary), any())
+ finishBind(mGroupChild1)
+ verify(mHeadsUpViewBinder, never()).bindHeadsUpView(eq(mGroupChild2), any())
+
+ verify(mHeadsUpManager, never()).showNotification(mGroupSummary)
+ verify(mHeadsUpManager).showNotification(mGroupChild1)
+ verify(mHeadsUpManager, never()).showNotification(mGroupChild2)
+ assertFalse(mGroupSummary.hasInterrupted())
+ }
+
+ @Test
fun testOnRankingApplied_newEntryShouldAlert() {
// GIVEN that mEntry has never interrupted in the past, and now should
// and is new enough to do so
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionRepository.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionRepository.kt
index de1fec8..288f54c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionRepository.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionRepository.kt
@@ -17,16 +17,18 @@
package com.android.systemui.statusbar.pipeline.mobile.data.repository
import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileSubscriptionModel
-import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
class FakeMobileConnectionRepository : MobileConnectionRepository {
private val _subscriptionsModelFlow = MutableStateFlow(MobileSubscriptionModel())
- override val subscriptionModelFlow: Flow<MobileSubscriptionModel> = _subscriptionsModelFlow
+ override val subscriptionModelFlow = _subscriptionsModelFlow
private val _dataEnabled = MutableStateFlow(true)
override val dataEnabled = _dataEnabled
+ private val _isDefaultDataSubscription = MutableStateFlow(true)
+ override val isDefaultDataSubscription = _isDefaultDataSubscription
+
fun setMobileSubscriptionModel(model: MobileSubscriptionModel) {
_subscriptionsModelFlow.value = model
}
@@ -34,4 +36,8 @@
fun setDataEnabled(enabled: Boolean) {
_dataEnabled.value = enabled
}
+
+ fun setIsDefaultDataSubscription(isDefault: Boolean) {
+ _isDefaultDataSubscription.value = isDefault
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionsRepository.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionsRepository.kt
index 813e750..533d5d9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionsRepository.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionsRepository.kt
@@ -17,8 +17,9 @@
package com.android.systemui.statusbar.pipeline.mobile.data.repository
import android.telephony.SubscriptionInfo
-import android.telephony.SubscriptionManager
+import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID
import com.android.settingslib.mobile.MobileMappings.Config
+import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectivityModel
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
@@ -26,18 +27,26 @@
private val _subscriptionsFlow = MutableStateFlow<List<SubscriptionInfo>>(listOf())
override val subscriptionsFlow: Flow<List<SubscriptionInfo>> = _subscriptionsFlow
- private val _activeMobileDataSubscriptionId =
- MutableStateFlow(SubscriptionManager.INVALID_SUBSCRIPTION_ID)
+ private val _activeMobileDataSubscriptionId = MutableStateFlow(INVALID_SUBSCRIPTION_ID)
override val activeMobileDataSubscriptionId = _activeMobileDataSubscriptionId
private val _defaultDataSubRatConfig = MutableStateFlow(Config())
override val defaultDataSubRatConfig = _defaultDataSubRatConfig
+ private val _defaultDataSubId = MutableStateFlow(INVALID_SUBSCRIPTION_ID)
+ override val defaultDataSubId = _defaultDataSubId
+
+ private val _mobileConnectivity = MutableStateFlow(MobileConnectivityModel())
+ override val defaultMobileNetworkConnectivity = _mobileConnectivity
+
private val subIdRepos = mutableMapOf<Int, MobileConnectionRepository>()
override fun getRepoForSubId(subId: Int): MobileConnectionRepository {
return subIdRepos[subId] ?: FakeMobileConnectionRepository().also { subIdRepos[subId] = it }
}
+ private val _globalMobileDataSettingChangedEvent = MutableStateFlow(Unit)
+ override val globalMobileDataSettingChangedEvent = _globalMobileDataSettingChangedEvent
+
fun setSubscriptions(subs: List<SubscriptionInfo>) {
_subscriptionsFlow.value = subs
}
@@ -46,6 +55,18 @@
_defaultDataSubRatConfig.value = config
}
+ fun setDefaultDataSubId(id: Int) {
+ _defaultDataSubId.value = id
+ }
+
+ fun setMobileConnectivity(model: MobileConnectivityModel) {
+ _mobileConnectivity.value = model
+ }
+
+ suspend fun triggerGlobalMobileDataSettingChangedEvent() {
+ _globalMobileDataSettingChangedEvent.emit(Unit)
+ }
+
fun setActiveMobileDataSubscriptionId(subId: Int) {
_activeMobileDataSubscriptionId.value = subId
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeUserSetupRepository.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeUserSetupRepository.kt
index 6c495c5..141b50c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeUserSetupRepository.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeUserSetupRepository.kt
@@ -16,13 +16,12 @@
package com.android.systemui.statusbar.pipeline.mobile.data.repository
-import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
/** Defaults to `true` */
class FakeUserSetupRepository : UserSetupRepository {
private val _isUserSetup: MutableStateFlow<Boolean> = MutableStateFlow(true)
- override val isUserSetupFlow: Flow<Boolean> = _isUserSetup
+ override val isUserSetupFlow = _isUserSetup
fun setUserSetup(setup: Boolean) {
_isUserSetup.value = setup
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionRepositoryTest.kt
index 0939364..5ce51bb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionRepositoryTest.kt
@@ -16,6 +16,8 @@
package com.android.systemui.statusbar.pipeline.mobile.data.repository
+import android.os.UserHandle
+import android.provider.Settings
import android.telephony.CellSignalStrengthCdma
import android.telephony.ServiceState
import android.telephony.SignalStrength
@@ -42,6 +44,7 @@
import com.android.systemui.util.mockito.argumentCaptor
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.CoroutineScope
import kotlinx.coroutines.Dispatchers
@@ -67,16 +70,23 @@
@Mock private lateinit var logger: ConnectivityPipelineLogger
private val scope = CoroutineScope(IMMEDIATE)
+ private val globalSettings = FakeSettings()
+ private val connectionsRepo = FakeMobileConnectionsRepository()
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
+ globalSettings.userId = UserHandle.USER_ALL
whenever(telephonyManager.subscriptionId).thenReturn(SUB_1_ID)
underTest =
MobileConnectionRepositoryImpl(
+ context,
SUB_1_ID,
telephonyManager,
+ globalSettings,
+ connectionsRepo.defaultDataSubId,
+ connectionsRepo.globalMobileDataSettingChangedEvent,
IMMEDIATE,
logger,
scope,
@@ -290,14 +300,20 @@
}
@Test
- fun dataEnabled_isEnabled() =
+ fun dataEnabled_initial_false() =
runBlocking(IMMEDIATE) {
whenever(telephonyManager.isDataConnectionAllowed).thenReturn(true)
- var latest: Boolean? = null
- val job = underTest.dataEnabled.onEach { latest = it }.launchIn(this)
+ assertThat(underTest.dataEnabled.value).isFalse()
+ }
- assertThat(latest).isTrue()
+ @Test
+ fun dataEnabled_isEnabled_true() =
+ runBlocking(IMMEDIATE) {
+ whenever(telephonyManager.isDataConnectionAllowed).thenReturn(true)
+ val job = underTest.dataEnabled.launchIn(this)
+
+ assertThat(underTest.dataEnabled.value).isTrue()
job.cancel()
}
@@ -306,10 +322,59 @@
fun dataEnabled_isDisabled() =
runBlocking(IMMEDIATE) {
whenever(telephonyManager.isDataConnectionAllowed).thenReturn(false)
+ val job = underTest.dataEnabled.launchIn(this)
+
+ assertThat(underTest.dataEnabled.value).isFalse()
+
+ job.cancel()
+ }
+
+ @Test
+ fun isDefaultDataSubscription_isDefault() =
+ runBlocking(IMMEDIATE) {
+ connectionsRepo.setDefaultDataSubId(SUB_1_ID)
+
+ var latest: Boolean? = null
+ val job = underTest.isDefaultDataSubscription.onEach { latest = it }.launchIn(this)
+
+ assertThat(latest).isTrue()
+
+ job.cancel()
+ }
+
+ @Test
+ fun isDefaultDataSubscription_isNotDefault() =
+ runBlocking(IMMEDIATE) {
+ // Our subId is SUB_1_ID
+ connectionsRepo.setDefaultDataSubId(123)
+
+ var latest: Boolean? = null
+ val job = underTest.isDefaultDataSubscription.onEach { latest = it }.launchIn(this)
+
+ assertThat(latest).isFalse()
+
+ job.cancel()
+ }
+
+ @Test
+ fun isDataConnectionAllowed_subIdSettingUpdate_valueUpdated() =
+ runBlocking(IMMEDIATE) {
+ val subIdSettingName = "${Settings.Global.MOBILE_DATA}$SUB_1_ID"
var latest: Boolean? = null
val job = underTest.dataEnabled.onEach { latest = it }.launchIn(this)
+ // We don't read the setting directly, we query telephony when changes happen
+ whenever(telephonyManager.isDataConnectionAllowed).thenReturn(false)
+ globalSettings.putInt(subIdSettingName, 0)
+ assertThat(latest).isFalse()
+
+ whenever(telephonyManager.isDataConnectionAllowed).thenReturn(true)
+ globalSettings.putInt(subIdSettingName, 1)
+ assertThat(latest).isTrue()
+
+ whenever(telephonyManager.isDataConnectionAllowed).thenReturn(false)
+ globalSettings.putInt(subIdSettingName, 0)
assertThat(latest).isFalse()
job.cancel()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepositoryTest.kt
index 326e0d281..a953a3d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepositoryTest.kt
@@ -16,26 +16,33 @@
package com.android.systemui.statusbar.pipeline.mobile.data.repository
+import android.content.Intent
+import android.net.ConnectivityManager
+import android.net.Network
+import android.net.NetworkCapabilities
+import android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED
+import android.net.NetworkCapabilities.TRANSPORT_CELLULAR
+import android.provider.Settings
import android.telephony.SubscriptionInfo
import android.telephony.SubscriptionManager
import android.telephony.TelephonyCallback
import android.telephony.TelephonyCallback.ActiveDataSubscriptionIdListener
import android.telephony.TelephonyManager
import androidx.test.filters.SmallTest
+import com.android.internal.telephony.PhoneConstants
import com.android.systemui.SysuiTestCase
-import com.android.systemui.broadcast.BroadcastDispatcher
+import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectivityModel
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.argumentCaptor
import com.android.systemui.util.mockito.mock
-import com.android.systemui.util.mockito.nullable
import com.android.systemui.util.mockito.whenever
+import com.android.systemui.util.settings.FakeSettings
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.cancel
-import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.runBlocking
@@ -43,7 +50,6 @@
import org.junit.Assert.assertThrows
import org.junit.Before
import org.junit.Test
-import org.mockito.ArgumentMatchers
import org.mockito.Mock
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
@@ -54,32 +60,26 @@
class MobileConnectionsRepositoryTest : SysuiTestCase() {
private lateinit var underTest: MobileConnectionsRepositoryImpl
+ @Mock private lateinit var connectivityManager: ConnectivityManager
@Mock private lateinit var subscriptionManager: SubscriptionManager
@Mock private lateinit var telephonyManager: TelephonyManager
@Mock private lateinit var logger: ConnectivityPipelineLogger
- @Mock private lateinit var broadcastDispatcher: BroadcastDispatcher
private val scope = CoroutineScope(IMMEDIATE)
+ private val globalSettings = FakeSettings()
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
- whenever(
- broadcastDispatcher.broadcastFlow(
- any(),
- nullable(),
- ArgumentMatchers.anyInt(),
- nullable(),
- )
- )
- .thenReturn(flowOf(Unit))
underTest =
MobileConnectionsRepositoryImpl(
+ connectivityManager,
subscriptionManager,
telephonyManager,
logger,
- broadcastDispatcher,
+ fakeBroadcastDispatcher,
+ globalSettings,
context,
IMMEDIATE,
scope,
@@ -214,6 +214,139 @@
job.cancel()
}
+ @Test
+ fun testDefaultDataSubId_updatesOnBroadcast() =
+ runBlocking(IMMEDIATE) {
+ var latest: Int? = null
+ val job = underTest.defaultDataSubId.onEach { latest = it }.launchIn(this)
+
+ fakeBroadcastDispatcher.registeredReceivers.forEach { receiver ->
+ receiver.onReceive(
+ context,
+ Intent(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED)
+ .putExtra(PhoneConstants.SUBSCRIPTION_KEY, SUB_2_ID)
+ )
+ }
+
+ assertThat(latest).isEqualTo(SUB_2_ID)
+
+ fakeBroadcastDispatcher.registeredReceivers.forEach { receiver ->
+ receiver.onReceive(
+ context,
+ Intent(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED)
+ .putExtra(PhoneConstants.SUBSCRIPTION_KEY, SUB_1_ID)
+ )
+ }
+
+ assertThat(latest).isEqualTo(SUB_1_ID)
+
+ job.cancel()
+ }
+
+ @Test
+ fun mobileConnectivity_default() {
+ assertThat(underTest.defaultMobileNetworkConnectivity.value)
+ .isEqualTo(MobileConnectivityModel(isConnected = false, isValidated = false))
+ }
+
+ @Test
+ fun mobileConnectivity_isConnected_isValidated() =
+ runBlocking(IMMEDIATE) {
+ val caps = createCapabilities(connected = true, validated = true)
+
+ var latest: MobileConnectivityModel? = null
+ val job =
+ underTest.defaultMobileNetworkConnectivity.onEach { latest = it }.launchIn(this)
+
+ getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, caps)
+
+ assertThat(latest)
+ .isEqualTo(MobileConnectivityModel(isConnected = true, isValidated = true))
+
+ job.cancel()
+ }
+
+ @Test
+ fun globalMobileDataSettingsChangedEvent_producesOnSettingChange() =
+ runBlocking(IMMEDIATE) {
+ var produced = false
+ val job =
+ underTest.globalMobileDataSettingChangedEvent
+ .onEach { produced = true }
+ .launchIn(this)
+
+ assertThat(produced).isFalse()
+
+ globalSettings.putInt(Settings.Global.MOBILE_DATA, 0)
+
+ assertThat(produced).isTrue()
+
+ job.cancel()
+ }
+
+ @Test
+ fun mobileConnectivity_isConnected_isNotValidated() =
+ runBlocking(IMMEDIATE) {
+ val caps = createCapabilities(connected = true, validated = false)
+
+ var latest: MobileConnectivityModel? = null
+ val job =
+ underTest.defaultMobileNetworkConnectivity.onEach { latest = it }.launchIn(this)
+
+ getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, caps)
+
+ assertThat(latest)
+ .isEqualTo(MobileConnectivityModel(isConnected = true, isValidated = false))
+
+ job.cancel()
+ }
+
+ @Test
+ fun mobileConnectivity_isNotConnected_isNotValidated() =
+ runBlocking(IMMEDIATE) {
+ val caps = createCapabilities(connected = false, validated = false)
+
+ var latest: MobileConnectivityModel? = null
+ val job =
+ underTest.defaultMobileNetworkConnectivity.onEach { latest = it }.launchIn(this)
+
+ getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, caps)
+
+ assertThat(latest)
+ .isEqualTo(MobileConnectivityModel(isConnected = false, isValidated = false))
+
+ job.cancel()
+ }
+
+ /** In practice, I don't think this state can ever happen (!connected, validated) */
+ @Test
+ fun mobileConnectivity_isNotConnected_isValidated() =
+ runBlocking(IMMEDIATE) {
+ val caps = createCapabilities(connected = false, validated = true)
+
+ var latest: MobileConnectivityModel? = null
+ val job =
+ underTest.defaultMobileNetworkConnectivity.onEach { latest = it }.launchIn(this)
+
+ getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, caps)
+
+ assertThat(latest).isEqualTo(MobileConnectivityModel(false, true))
+
+ job.cancel()
+ }
+
+ private fun createCapabilities(connected: Boolean, validated: Boolean): NetworkCapabilities =
+ mock<NetworkCapabilities>().also {
+ whenever(it.hasTransport(TRANSPORT_CELLULAR)).thenReturn(connected)
+ whenever(it.hasCapability(NET_CAPABILITY_VALIDATED)).thenReturn(validated)
+ }
+
+ private fun getDefaultNetworkCallback(): ConnectivityManager.NetworkCallback {
+ val callbackCaptor = argumentCaptor<ConnectivityManager.NetworkCallback>()
+ verify(connectivityManager).registerDefaultNetworkCallback(callbackCaptor.capture())
+ return callbackCaptor.value!!
+ }
+
private fun getSubscriptionCallback(): SubscriptionManager.OnSubscriptionsChangedListener {
val callbackCaptor = argumentCaptor<SubscriptionManager.OnSubscriptionsChangedListener>()
verify(subscriptionManager)
@@ -242,5 +375,8 @@
private const val SUB_2_ID = 2
private val SUB_2 =
mock<SubscriptionInfo>().also { whenever(it.subscriptionId).thenReturn(SUB_2_ID) }
+
+ private const val NET_ID = 123
+ private val NETWORK = mock<Network>().apply { whenever(getNetId()).thenReturn(NET_ID) }
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconInteractor.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconInteractor.kt
index 5611c44..3ae7d3c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconInteractor.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconInteractor.kt
@@ -28,18 +28,23 @@
private val _isEmergencyOnly = MutableStateFlow(false)
override val isEmergencyOnly = _isEmergencyOnly
+ private val _isFailedConnection = MutableStateFlow(false)
+ override val isDefaultConnectionFailed = _isFailedConnection
+
+ override val isDataConnected = MutableStateFlow(true)
+
private val _isDataEnabled = MutableStateFlow(true)
override val isDataEnabled = _isDataEnabled
+ private val _isDefaultDataEnabled = MutableStateFlow(true)
+ override val isDefaultDataEnabled = _isDefaultDataEnabled
+
private val _level = MutableStateFlow(CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN)
override val level = _level
private val _numberOfLevels = MutableStateFlow(4)
override val numberOfLevels = _numberOfLevels
- private val _cutOut = MutableStateFlow(false)
- override val cutOut = _cutOut
-
fun setIconGroup(group: SignalIcon.MobileIconGroup) {
_iconGroup.value = group
}
@@ -52,6 +57,14 @@
_isDataEnabled.value = enabled
}
+ fun setIsDefaultDataEnabled(disabled: Boolean) {
+ _isDefaultDataEnabled.value = disabled
+ }
+
+ fun setIsFailedConnection(failed: Boolean) {
+ _isFailedConnection.value = failed
+ }
+
fun setLevel(level: Int) {
_level.value = level
}
@@ -59,8 +72,4 @@
fun setNumberOfLevels(num: Int) {
_numberOfLevels.value = num
}
-
- fun setCutOut(cutOut: Boolean) {
- _cutOut.value = cutOut
- }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconsInteractor.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconsInteractor.kt
index 2bd2286..061c3b54 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconsInteractor.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconsInteractor.kt
@@ -26,8 +26,7 @@
import com.android.systemui.statusbar.pipeline.mobile.util.MobileMappingsProxy
import kotlinx.coroutines.flow.MutableStateFlow
-class FakeMobileIconsInteractor(private val mobileMappings: MobileMappingsProxy) :
- MobileIconsInteractor {
+class FakeMobileIconsInteractor(mobileMappings: MobileMappingsProxy) : MobileIconsInteractor {
val THREE_G_KEY = mobileMappings.toIconKey(THREE_G)
val LTE_KEY = mobileMappings.toIconKey(LTE)
val FOUR_G_KEY = mobileMappings.toIconKey(FOUR_G)
@@ -46,9 +45,14 @@
FIVE_G_OVERRIDE_KEY to TelephonyIcons.NR_5G,
)
+ override val isDefaultConnectionFailed = MutableStateFlow(false)
+
private val _filteredSubscriptions = MutableStateFlow<List<SubscriptionInfo>>(listOf())
override val filteredSubscriptions = _filteredSubscriptions
+ private val _activeDataConnectionHasDataEnabled = MutableStateFlow(false)
+ override val activeDataConnectionHasDataEnabled = _activeDataConnectionHasDataEnabled
+
private val _defaultMobileIconMapping = MutableStateFlow(TEST_MAPPING)
override val defaultMobileIconMapping = _defaultMobileIconMapping
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt
index ff44af4..7fc1c0f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt
@@ -23,6 +23,7 @@
import com.android.settingslib.SignalIcon.MobileIconGroup
import com.android.settingslib.mobile.TelephonyIcons
import com.android.systemui.SysuiTestCase
+import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState
import com.android.systemui.statusbar.pipeline.mobile.data.model.DefaultNetworkType
import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileSubscriptionModel
import com.android.systemui.statusbar.pipeline.mobile.data.model.OverrideNetworkType
@@ -34,6 +35,7 @@
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
@@ -49,12 +51,17 @@
private val mobileIconsInteractor = FakeMobileIconsInteractor(mobileMappingsProxy)
private val connectionRepository = FakeMobileConnectionRepository()
+ private val scope = CoroutineScope(IMMEDIATE)
+
@Before
fun setUp() {
underTest =
MobileIconInteractorImpl(
+ scope,
+ mobileIconsInteractor.activeDataConnectionHasDataEnabled,
mobileIconsInteractor.defaultMobileIconMapping,
mobileIconsInteractor.defaultMobileIconGroup,
+ mobileIconsInteractor.isDefaultConnectionFailed,
mobileMappingsProxy,
connectionRepository,
)
@@ -196,6 +203,66 @@
job.cancel()
}
+ @Test
+ fun test_isDefaultDataEnabled_matchesParent() =
+ runBlocking(IMMEDIATE) {
+ var latest: Boolean? = null
+ val job = underTest.isDefaultDataEnabled.onEach { latest = it }.launchIn(this)
+
+ mobileIconsInteractor.activeDataConnectionHasDataEnabled.value = true
+ assertThat(latest).isTrue()
+
+ mobileIconsInteractor.activeDataConnectionHasDataEnabled.value = false
+ assertThat(latest).isFalse()
+
+ job.cancel()
+ }
+
+ @Test
+ fun test_isDefaultConnectionFailed_matchedParent() =
+ runBlocking(IMMEDIATE) {
+ val job = underTest.isDefaultConnectionFailed.launchIn(this)
+
+ mobileIconsInteractor.isDefaultConnectionFailed.value = false
+ assertThat(underTest.isDefaultConnectionFailed.value).isFalse()
+
+ mobileIconsInteractor.isDefaultConnectionFailed.value = true
+ assertThat(underTest.isDefaultConnectionFailed.value).isTrue()
+
+ job.cancel()
+ }
+
+ @Test
+ fun dataState_connected() =
+ runBlocking(IMMEDIATE) {
+ var latest: Boolean? = null
+ val job = underTest.isDataConnected.onEach { latest = it }.launchIn(this)
+
+ connectionRepository.setMobileSubscriptionModel(
+ MobileSubscriptionModel(dataConnectionState = DataConnectionState.Connected)
+ )
+ yield()
+
+ assertThat(latest).isTrue()
+
+ job.cancel()
+ }
+
+ @Test
+ fun dataState_notConnected() =
+ runBlocking(IMMEDIATE) {
+ var latest: Boolean? = null
+ val job = underTest.isDataConnected.onEach { latest = it }.launchIn(this)
+
+ connectionRepository.setMobileSubscriptionModel(
+ MobileSubscriptionModel(dataConnectionState = DataConnectionState.Disconnected)
+ )
+
+ assertThat(latest).isFalse()
+
+ job.cancel()
+ }
+
companion object {
private val IMMEDIATE = Dispatchers.Main.immediate
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt
index 877ce0e..b56dcd7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt
@@ -17,8 +17,10 @@
package com.android.systemui.statusbar.pipeline.mobile.domain.interactor
import android.telephony.SubscriptionInfo
+import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileConnectivityModel
import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionRepository
import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionsRepository
import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeUserSetupRepository
@@ -32,6 +34,7 @@
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.yield
import org.junit.After
import org.junit.Before
import org.junit.Test
@@ -168,6 +171,92 @@
job.cancel()
}
+ @Test
+ fun activeDataConnection_turnedOn() =
+ runBlocking(IMMEDIATE) {
+ CONNECTION_1.setDataEnabled(true)
+ var latest: Boolean? = null
+ val job =
+ underTest.activeDataConnectionHasDataEnabled.onEach { latest = it }.launchIn(this)
+
+ assertThat(latest).isTrue()
+
+ job.cancel()
+ }
+
+ @Test
+ fun activeDataConnection_turnedOff() =
+ runBlocking(IMMEDIATE) {
+ CONNECTION_1.setDataEnabled(true)
+ var latest: Boolean? = null
+ val job =
+ underTest.activeDataConnectionHasDataEnabled.onEach { latest = it }.launchIn(this)
+
+ CONNECTION_1.setDataEnabled(false)
+ yield()
+
+ assertThat(latest).isFalse()
+
+ job.cancel()
+ }
+
+ @Test
+ fun activeDataConnection_invalidSubId() =
+ runBlocking(IMMEDIATE) {
+ var latest: Boolean? = null
+ val job =
+ underTest.activeDataConnectionHasDataEnabled.onEach { latest = it }.launchIn(this)
+
+ connectionsRepository.setActiveMobileDataSubscriptionId(INVALID_SUBSCRIPTION_ID)
+ yield()
+
+ // An invalid active subId should tell us that data is off
+ assertThat(latest).isFalse()
+
+ job.cancel()
+ }
+
+ @Test
+ fun failedConnection_connected_validated_notFailed() =
+ runBlocking(IMMEDIATE) {
+ var latest: Boolean? = null
+ val job = underTest.isDefaultConnectionFailed.onEach { latest = it }.launchIn(this)
+ connectionsRepository.setMobileConnectivity(MobileConnectivityModel(true, true))
+ yield()
+
+ assertThat(latest).isFalse()
+
+ job.cancel()
+ }
+
+ @Test
+ fun failedConnection_notConnected_notValidated_notFailed() =
+ runBlocking(IMMEDIATE) {
+ var latest: Boolean? = null
+ val job = underTest.isDefaultConnectionFailed.onEach { latest = it }.launchIn(this)
+
+ connectionsRepository.setMobileConnectivity(MobileConnectivityModel(false, false))
+ yield()
+
+ assertThat(latest).isFalse()
+
+ job.cancel()
+ }
+
+ @Test
+ fun failedConnection_connected_notValidated_failed() =
+ runBlocking(IMMEDIATE) {
+ var latest: Boolean? = null
+ val job = underTest.isDefaultConnectionFailed.onEach { latest = it }.launchIn(this)
+
+ connectionsRepository.setMobileConnectivity(MobileConnectivityModel(true, false))
+ yield()
+
+ assertThat(latest).isTrue()
+
+ job.cancel()
+ }
+
companion object {
private val IMMEDIATE = Dispatchers.Main.immediate
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt
index ce0f33f..d4c2c3f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt
@@ -46,10 +46,12 @@
MockitoAnnotations.initMocks(this)
interactor.apply {
setLevel(1)
- setCutOut(false)
+ setIsDefaultDataEnabled(true)
+ setIsFailedConnection(false)
setIconGroup(THREE_G)
setIsEmergencyOnly(false)
setNumberOfLevels(4)
+ isDataConnected.value = true
}
underTest = MobileIconViewModel(SUB_1_ID, interactor, logger)
}
@@ -59,8 +61,23 @@
runBlocking(IMMEDIATE) {
var latest: Int? = null
val job = underTest.iconId.onEach { latest = it }.launchIn(this)
+ val expected = defaultSignal()
- assertThat(latest).isEqualTo(SignalDrawable.getState(1, 4, false))
+ assertThat(latest).isEqualTo(expected)
+
+ job.cancel()
+ }
+
+ @Test
+ fun iconId_cutout_whenDefaultDataDisabled() =
+ runBlocking(IMMEDIATE) {
+ interactor.setIsDefaultDataEnabled(false)
+
+ var latest: Int? = null
+ val job = underTest.iconId.onEach { latest = it }.launchIn(this)
+ val expected = defaultSignal(level = 1, connected = false)
+
+ assertThat(latest).isEqualTo(expected)
job.cancel()
}
@@ -97,6 +114,44 @@
}
@Test
+ fun networkType_nullWhenFailedConnection() =
+ runBlocking(IMMEDIATE) {
+ interactor.setIconGroup(THREE_G)
+ interactor.setIsDataEnabled(true)
+ interactor.setIsFailedConnection(true)
+ var latest: Icon? = null
+ val job = underTest.networkTypeIcon.onEach { latest = it }.launchIn(this)
+
+ assertThat(latest).isNull()
+
+ job.cancel()
+ }
+
+ @Test
+ fun networkType_nullWhenDataDisconnects() =
+ runBlocking(IMMEDIATE) {
+ val initial =
+ Icon.Resource(
+ THREE_G.dataType,
+ ContentDescription.Resource(THREE_G.dataContentDescription)
+ )
+
+ interactor.setIconGroup(THREE_G)
+ var latest: Icon? = null
+ val job = underTest.networkTypeIcon.onEach { latest = it }.launchIn(this)
+
+ interactor.setIconGroup(THREE_G)
+ assertThat(latest).isEqualTo(initial)
+
+ interactor.isDataConnected.value = false
+ yield()
+
+ assertThat(latest).isNull()
+
+ job.cancel()
+ }
+
+ @Test
fun networkType_null_changeToDisabled() =
runBlocking(IMMEDIATE) {
val expected =
@@ -119,6 +174,14 @@
job.cancel()
}
+ /** Convenience constructor for these tests */
+ private fun defaultSignal(
+ level: Int = 1,
+ connected: Boolean = true,
+ ): Int {
+ return SignalDrawable.getState(level, /* numLevels */ 4, !connected)
+ }
+
companion object {
private val IMMEDIATE = Dispatchers.Main.immediate
private const val SUB_1_ID = 1
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/GuestUserInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/GuestUserInteractorTest.kt
index 120bf79..e496521 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/GuestUserInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/GuestUserInteractorTest.kt
@@ -219,6 +219,7 @@
repository.setUserInfos(listOf(NON_GUEST_USER_INFO, EPHEMERAL_GUEST_USER_INFO))
repository.setSelectedUserInfo(EPHEMERAL_GUEST_USER_INFO)
val targetUserId = NON_GUEST_USER_INFO.id
+ val ephemeralGuestUserHandle = UserHandle.of(EPHEMERAL_GUEST_USER_INFO.id)
underTest.exit(
guestUserId = GUEST_USER_INFO.id,
@@ -230,7 +231,7 @@
)
verify(manager).markGuestForDeletion(EPHEMERAL_GUEST_USER_INFO.id)
- verify(manager).removeUser(EPHEMERAL_GUEST_USER_INFO.id)
+ verify(manager).removeUserWhenPossible(ephemeralGuestUserHandle, false)
verify(switchUser).invoke(targetUserId)
}
@@ -240,6 +241,7 @@
whenever(manager.markGuestForDeletion(anyInt())).thenReturn(true)
repository.setSelectedUserInfo(GUEST_USER_INFO)
val targetUserId = NON_GUEST_USER_INFO.id
+ val guestUserHandle = UserHandle.of(GUEST_USER_INFO.id)
underTest.exit(
guestUserId = GUEST_USER_INFO.id,
@@ -251,7 +253,7 @@
)
verify(manager).markGuestForDeletion(GUEST_USER_INFO.id)
- verify(manager).removeUser(GUEST_USER_INFO.id)
+ verify(manager).removeUserWhenPossible(guestUserHandle, false)
verify(switchUser).invoke(targetUserId)
}
@@ -296,6 +298,7 @@
repository.setSelectedUserInfo(GUEST_USER_INFO)
val targetUserId = NON_GUEST_USER_INFO.id
+ val guestUserHandle = UserHandle.of(GUEST_USER_INFO.id)
underTest.remove(
guestUserId = GUEST_USER_INFO.id,
targetUserId = targetUserId,
@@ -305,7 +308,7 @@
)
verify(manager).markGuestForDeletion(GUEST_USER_INFO.id)
- verify(manager).removeUser(GUEST_USER_INFO.id)
+ verify(manager).removeUserWhenPossible(guestUserHandle, false)
verify(switchUser).invoke(targetUserId)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wallpapers/ImageWallpaperTest.java b/packages/SystemUI/tests/src/com/android/systemui/wallpapers/ImageWallpaperTest.java
index c254358..379bb28 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wallpapers/ImageWallpaperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wallpapers/ImageWallpaperTest.java
@@ -26,8 +26,8 @@
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -44,6 +44,7 @@
import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayManagerGlobal;
import android.os.Handler;
+import android.os.UserHandle;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.Display;
@@ -135,9 +136,10 @@
when(mWallpaperBitmap.getHeight()).thenReturn(mBitmapHeight);
// set up wallpaper manager
- when(mWallpaperManager.peekBitmapDimensions()).thenReturn(
- new Rect(0, 0, mBitmapWidth, mBitmapHeight));
- when(mWallpaperManager.getBitmap(false)).thenReturn(mWallpaperBitmap);
+ when(mWallpaperManager.peekBitmapDimensions())
+ .thenReturn(new Rect(0, 0, mBitmapWidth, mBitmapHeight));
+ when(mWallpaperManager.getBitmapAsUser(eq(UserHandle.USER_CURRENT), anyBoolean()))
+ .thenReturn(mWallpaperBitmap);
when(mMockContext.getSystemService(WallpaperManager.class)).thenReturn(mWallpaperManager);
// set up surface
@@ -286,9 +288,6 @@
testMinSurfaceHelper(8, 8);
testMinSurfaceHelper(100, 2000);
testMinSurfaceHelper(200, 1);
- testMinSurfaceHelper(0, 1);
- testMinSurfaceHelper(1, 0);
- testMinSurfaceHelper(0, 0);
}
private void testMinSurfaceHelper(int bitmapWidth, int bitmapHeight) {
@@ -307,28 +306,6 @@
}
@Test
- public void testZeroBitmap() {
- // test that a frame is never drawn with a 0 bitmap
- testZeroBitmapHelper(0, 1);
- testZeroBitmapHelper(1, 0);
- testZeroBitmapHelper(0, 0);
- }
-
- private void testZeroBitmapHelper(int bitmapWidth, int bitmapHeight) {
-
- clearInvocations(mSurfaceHolder);
- setBitmapDimensions(bitmapWidth, bitmapHeight);
-
- ImageWallpaper imageWallpaper = createImageWallpaperCanvas();
- ImageWallpaper.CanvasEngine engine =
- (ImageWallpaper.CanvasEngine) imageWallpaper.onCreateEngine();
- ImageWallpaper.CanvasEngine spyEngine = spy(engine);
- spyEngine.onCreate(mSurfaceHolder);
- spyEngine.onSurfaceRedrawNeeded(mSurfaceHolder);
- verify(spyEngine, never()).drawFrameOnCanvas(any());
- }
-
- @Test
public void testLoadDrawAndUnloadBitmap() {
setBitmapDimensions(LOW_BMP_WIDTH, LOW_BMP_HEIGHT);
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
index 0c12680..11178db 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
@@ -19,6 +19,7 @@
import com.android.systemui.common.shared.model.Position
import com.android.systemui.keyguard.shared.model.StatusBarState
+import com.android.systemui.keyguard.shared.model.WakefulnessModel
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
@@ -48,6 +49,9 @@
private val _statusBarState = MutableStateFlow(StatusBarState.SHADE)
override val statusBarState: Flow<StatusBarState> = _statusBarState
+ private val _wakefulnessState = MutableStateFlow(WakefulnessModel.ASLEEP)
+ override val wakefulnessState: Flow<WakefulnessModel> = _wakefulnessState
+
override fun isKeyguardShowing(): Boolean {
return _isKeyguardShowing.value
}
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
new file mode 100644
index 0000000..6c44244
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardTransitionRepository.kt
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.keyguard.data.repository
+
+import android.annotation.FloatRange
+import com.android.systemui.keyguard.shared.model.TransitionInfo
+import com.android.systemui.keyguard.shared.model.TransitionState
+import com.android.systemui.keyguard.shared.model.TransitionStep
+import java.util.UUID
+import kotlinx.coroutines.flow.MutableSharedFlow
+import kotlinx.coroutines.flow.SharedFlow
+
+/** Fake implementation of [KeyguardTransitionRepository] */
+class FakeKeyguardTransitionRepository : KeyguardTransitionRepository {
+
+ private val _transitions = MutableSharedFlow<TransitionStep>()
+ override val transitions: SharedFlow<TransitionStep> = _transitions
+
+ suspend fun sendTransitionStep(step: TransitionStep) {
+ _transitions.emit(step)
+ }
+
+ override fun startTransition(info: TransitionInfo): UUID? {
+ return null
+ }
+
+ override fun updateTransition(
+ transitionId: UUID,
+ @FloatRange(from = 0.0, to = 1.0) value: Float,
+ state: TransitionState
+ ) = Unit
+}
diff --git a/packages/VpnDialogs/res/values-es-rUS/strings.xml b/packages/VpnDialogs/res/values-es-rUS/strings.xml
index 108a24e..232b53a 100644
--- a/packages/VpnDialogs/res/values-es-rUS/strings.xml
+++ b/packages/VpnDialogs/res/values-es-rUS/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="prompt" msgid="3183836924226407828">"Solicitud de conexión"</string>
- <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> quiere configurar una conexión VPN capaz de controlar el tráfico de la red. Acéptala solo si confías en la fuente. <br /> <br /> <img src=vpn_icon /> aparece en la parte superior de la pantalla cuando se activa la VPN."</string>
+ <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> quiere configurar una conexión VPN capaz de supervisar el tráfico de la red. Acéptala solo si confías en la fuente. <br /> <br /> <img src=vpn_icon /> aparece en la parte superior de la pantalla cuando se activa la VPN."</string>
<string name="warning" product="tv" msgid="5188957997628124947">"<xliff:g id="APP">%s</xliff:g> quiere configurar una conexión VPN que le permita supervisar el tráfico de red. Solo acéptala si confías en la fuente. <br /> <br /> <img src=vpn_icon /> aparecerá en tu pantalla cuando se active la VPN."</string>
<string name="legacy_title" msgid="192936250066580964">"La VPN está conectada."</string>
<string name="session" msgid="6470628549473641030">"Sesión:"</string>
diff --git a/packages/VpnDialogs/res/values-es/strings.xml b/packages/VpnDialogs/res/values-es/strings.xml
index 9bf86f5..4e21fd09 100644
--- a/packages/VpnDialogs/res/values-es/strings.xml
+++ b/packages/VpnDialogs/res/values-es/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="prompt" msgid="3183836924226407828">"Solicitud de conexión"</string>
- <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> quiere configurar una conexión VPN para controlar el tráfico de red. Solo debes aceptarla si confías en la fuente. <br /> <br /> <img src=vpn_icon /> aparece en la parte superior de la pantalla cuando se active la conexión VPN."</string>
+ <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> quiere configurar una conexión VPN para controlar el tráfico de red. Solo debes aceptarla si confías en la fuente. <br /> <br /> <img src=vpn_icon /> aparece en la parte superior de la pantalla cuando la conexión VPN está activa."</string>
<string name="warning" product="tv" msgid="5188957997628124947">"<xliff:g id="APP">%s</xliff:g> quiere configurar una conexión VPN que le permita monitorizar el tráfico de red. Acéptalo solo si confías en la fuente. <br /> <br /> <img src=vpn_icon /> aparecerá en la pantalla cuando la VPN esté activa."</string>
<string name="legacy_title" msgid="192936250066580964">"La VPN está conectada"</string>
<string name="session" msgid="6470628549473641030">"Sesión:"</string>
diff --git a/packages/VpnDialogs/res/values-nl/strings.xml b/packages/VpnDialogs/res/values-nl/strings.xml
index 33f8a89..76f56af 100644
--- a/packages/VpnDialogs/res/values-nl/strings.xml
+++ b/packages/VpnDialogs/res/values-nl/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="prompt" msgid="3183836924226407828">"Verbindingsverzoek"</string>
- <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> wil een VPN-verbinding opzetten om netwerkverkeer te controleren. Accepteer het verzoek alleen als je de bron vertrouwt. <br /> <br /> <img src=vpn_icon /> wordt boven aan je scherm weergegeven wanneer VPN actief is."</string>
+ <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> wil een VPN-verbinding instellen waarmee de app het netwerkverkeer kan bijhouden. Accepteer dit alleen als je de bron vertrouwt. <br /> <br /> <img src=vpn_icon /> verschijnt op je scherm als het VPN actief is."</string>
<string name="warning" product="tv" msgid="5188957997628124947">"<xliff:g id="APP">%s</xliff:g> wil een VPN-verbinding instellen waarmee de app het netwerkverkeer kan bijhouden. Accepteer dit alleen als je de bron vertrouwt. <br /> <br /> <img src=vpn_icon /> verschijnt op je scherm als het VPN actief is."</string>
<string name="legacy_title" msgid="192936250066580964">"Verbinding met VPN"</string>
<string name="session" msgid="6470628549473641030">"Sessie:"</string>
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 47b4156..e3ae03c 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -3651,6 +3651,10 @@
throw new IllegalArgumentException("The display " + displayId + " does not exist or is"
+ " not tracked by accessibility.");
}
+ if (mProxyManager.isProxyed(displayId)) {
+ throw new IllegalArgumentException("The display " + displayId + " is already being"
+ + "proxy-ed");
+ }
mProxyManager.registerProxy(client, displayId);
return true;
diff --git a/services/accessibility/java/com/android/server/accessibility/ProxyAccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/ProxyAccessibilityServiceConnection.java
index 934b665..247f320 100644
--- a/services/accessibility/java/com/android/server/accessibility/ProxyAccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/ProxyAccessibilityServiceConnection.java
@@ -32,6 +32,7 @@
import android.os.IBinder;
import android.os.RemoteCallback;
import android.view.KeyEvent;
+import android.view.accessibility.AccessibilityDisplayProxy;
import android.view.accessibility.AccessibilityNodeInfo;
import androidx.annotation.Nullable;
@@ -44,7 +45,7 @@
import java.util.Set;
/**
- * Represents the system connection to an {@link android.view.accessibility.AccessibilityProxy}.
+ * Represents the system connection to an {@link AccessibilityDisplayProxy}.
*
* <p>Most methods are no-ops since this connection does not need to capture input or listen to
* hardware-related changes.
diff --git a/services/accessibility/java/com/android/server/accessibility/ProxyManager.java b/services/accessibility/java/com/android/server/accessibility/ProxyManager.java
index fb0b8f3..a2ce610 100644
--- a/services/accessibility/java/com/android/server/accessibility/ProxyManager.java
+++ b/services/accessibility/java/com/android/server/accessibility/ProxyManager.java
@@ -16,6 +16,8 @@
package com.android.server.accessibility;
import android.accessibilityservice.IAccessibilityServiceClient;
+import java.util.HashSet;
+
/**
* Manages proxy connections.
*
@@ -26,6 +28,7 @@
*/
public class ProxyManager {
private final Object mLock;
+ private final HashSet<Integer> mDisplayIds = new HashSet<>();
ProxyManager(Object lock) {
mLock = lock;
@@ -35,12 +38,21 @@
* TODO: Create the proxy service connection.
*/
public void registerProxy(IAccessibilityServiceClient client, int displayId) {
+ mDisplayIds.add(displayId);
}
/**
* TODO: Unregister the proxy service connection based on display id.
*/
public boolean unregisterProxy(int displayId) {
+ mDisplayIds.remove(displayId);
return true;
}
+
+ /**
+ * Checks if a display id is being proxy-ed.
+ */
+ public boolean isProxyed(int displayId) {
+ return mDisplayIds.contains(displayId);
+ }
}
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 47ce592..64b7688 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.FillEventHistory.Event.UI_TYPE_UNKNOWN;
import static android.service.autofill.FillRequest.FLAG_MANUAL_REQUEST;
import static android.service.autofill.FillRequest.FLAG_PASSWORD_INPUT_TYPE;
+import static android.service.autofill.FillRequest.FLAG_RESET_FILL_DIALOG_STATE;
import static android.service.autofill.FillRequest.FLAG_SUPPORTS_FILL_DIALOG;
import static android.service.autofill.FillRequest.FLAG_VIEW_NOT_FOCUSED;
import static android.service.autofill.FillRequest.INVALID_REQUEST_ID;
@@ -416,6 +417,14 @@
@GuardedBy("mLock")
private boolean mPreviouslyFillDialogPotentiallyStarted;
+ /**
+ * Keeps the fill dialog trigger ids of the last response. This invalidates
+ * the trigger ids of the previous response.
+ */
+ @Nullable
+ @GuardedBy("mLock")
+ private AutofillId[] mLastFillDialogTriggerIds;
+
void onSwitchInputMethodLocked() {
// One caveat is that for the case where the focus is on a field for which regular autofill
// returns null, and augmented autofill is triggered, and then the user switches the input
@@ -1222,6 +1231,8 @@
return;
}
+ mLastFillDialogTriggerIds = response.getFillDialogTriggerIds();
+
final int flags = response.getFlags();
if ((flags & FillResponse.FLAG_DELAY_FILL) != 0) {
Slog.v(TAG, "Service requested to wait for delayed fill response.");
@@ -1310,6 +1321,7 @@
// fallback to the default platform password manager
mSessionFlags.mClientSuggestionsEnabled = false;
+ mLastFillDialogTriggerIds = null;
final InlineSuggestionsRequest inlineRequest =
(mLastInlineSuggestionsRequest != null
@@ -1348,6 +1360,7 @@
+ (timedOut ? "timeout" : "failure"));
}
mService.resetLastResponse();
+ mLastFillDialogTriggerIds = null;
final LogMaker requestLog = mRequestLogs.get(requestId);
if (requestLog == null) {
Slog.w(TAG, "onFillRequestFailureOrTimeout(): no log for id " + requestId);
@@ -3049,6 +3062,11 @@
}
}
+ if ((flags & FLAG_RESET_FILL_DIALOG_STATE) != 0) {
+ if (sDebug) Log.d(TAG, "force to reset fill dialog state");
+ mSessionFlags.mFillDialogDisabled = false;
+ }
+
switch(action) {
case ACTION_START_SESSION:
// View is triggering autofill.
@@ -3488,10 +3506,8 @@
}
private boolean isFillDialogUiEnabled() {
- // TODO read from Settings or somewhere
- final boolean isSettingsEnabledFillDialog = true;
synchronized (mLock) {
- return isSettingsEnabledFillDialog && !mSessionFlags.mFillDialogDisabled;
+ return !mSessionFlags.mFillDialogDisabled;
}
}
@@ -3517,14 +3533,25 @@
AutofillId filledId, String filterText, int flags) {
if (!isFillDialogUiEnabled()) {
// Unsupported fill dialog UI
+ if (sDebug) Log.w(TAG, "requestShowFillDialog: fill dialog is disabled");
return false;
}
if ((flags & FillRequest.FLAG_IME_SHOWING) != 0) {
// IME is showing, fallback to normal suggestions UI
+ if (sDebug) Log.w(TAG, "requestShowFillDialog: IME is showing");
return false;
}
+ synchronized (mLock) {
+ if (mLastFillDialogTriggerIds == null
+ || !ArrayUtils.contains(mLastFillDialogTriggerIds, filledId)) {
+ // Last fill dialog triggered ids are changed.
+ if (sDebug) Log.w(TAG, "Last fill dialog triggered ids are changed.");
+ return false;
+ }
+ }
+
final Drawable serviceIcon = getServiceIcon();
getUiForShowing().showFillDialog(filledId, response, filterText,
@@ -4394,6 +4421,13 @@
if (mSessionFlags.mAugmentedAutofillOnly) {
pw.print(prefix); pw.println("For Augmented Autofill Only");
}
+ if (mSessionFlags.mFillDialogDisabled) {
+ pw.print(prefix); pw.println("Fill Dialog disabled");
+ }
+ if (mLastFillDialogTriggerIds != null) {
+ pw.print(prefix); pw.println("Last Fill Dialog trigger ids: ");
+ pw.println(mSelectedDatasetIds);
+ }
if (mAugmentedAutofillDestroyer != null) {
pw.print(prefix); pw.println("has mAugmentedAutofillDestroyer");
}
diff --git a/services/core/java/android/os/BatteryStatsInternal.java b/services/core/java/android/os/BatteryStatsInternal.java
index 41044bf..b70cbe3 100644
--- a/services/core/java/android/os/BatteryStatsInternal.java
+++ b/services/core/java/android/os/BatteryStatsInternal.java
@@ -27,7 +27,6 @@
import java.util.Collection;
import java.util.List;
-
/**
* Battery stats local system service interface. This is used to pass internal data out of
* BatteryStatsImpl, as well as make unchecked calls into BatteryStatsImpl.
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index ea66884..062afe9 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -470,6 +470,7 @@
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicLong;
import java.util.function.BiFunction;
public class ActivityManagerService extends IActivityManager.Stub
@@ -3455,13 +3456,13 @@
}
/**
- * @param firstPidOffsets Optional, when it's set, it receives the start/end offset
+ * @param firstPidEndOffset Optional, when it's set, it receives the start/end offset
* of the very first pid to be dumped.
*/
/* package */ static File dumpStackTraces(ArrayList<Integer> firstPids,
ProcessCpuTracker processCpuTracker, SparseArray<Boolean> lastPids,
ArrayList<Integer> nativePids, StringWriter logExceptionCreatingFile,
- long[] firstPidOffsets, String subject, String criticalEventSection,
+ AtomicLong firstPidEndOffset, String subject, String criticalEventSection,
AnrLatencyTracker latencyTracker) {
try {
if (latencyTracker != null) {
@@ -3534,15 +3535,10 @@
+ (criticalEventSection != null ? criticalEventSection : ""));
}
- Pair<Long, Long> offsets = dumpStackTraces(
+ long firstPidEndPos = dumpStackTraces(
tracesFile.getAbsolutePath(), firstPids, nativePids, extraPids, latencyTracker);
- if (firstPidOffsets != null) {
- if (offsets == null) {
- firstPidOffsets[0] = firstPidOffsets[1] = -1;
- } else {
- firstPidOffsets[0] = offsets.first; // Start offset to the ANR trace file
- firstPidOffsets[1] = offsets.second; // End offset to the ANR trace file
- }
+ if (firstPidEndOffset != null) {
+ firstPidEndOffset.set(firstPidEndPos);
}
return tracesFile;
@@ -3661,9 +3657,9 @@
/**
- * @return The start/end offset of the trace of the very first PID
+ * @return The end offset of the trace of the very first PID
*/
- public static Pair<Long, Long> dumpStackTraces(String tracesFile,
+ public static long dumpStackTraces(String tracesFile,
ArrayList<Integer> firstPids, ArrayList<Integer> nativePids,
ArrayList<Integer> extraPids, AnrLatencyTracker latencyTracker) {
@@ -3679,7 +3675,6 @@
// As applications are usually interested with the ANR stack traces, but we can't share with
// them the stack traces other than their own stacks. So after the very first PID is
// dumped, remember the current file size.
- long firstPidStart = -1;
long firstPidEnd = -1;
// First collect all of the stacks of the most important pids.
@@ -3692,11 +3687,6 @@
final int pid = firstPids.get(i);
// We don't copy ANR traces from the system_server intentionally.
final boolean firstPid = i == 0 && MY_PID != pid;
- File tf = null;
- if (firstPid) {
- tf = new File(tracesFile);
- firstPidStart = tf.exists() ? tf.length() : 0;
- }
if (latencyTracker != null) {
latencyTracker.dumpingPidStarted(pid);
}
@@ -3712,11 +3702,11 @@
if (remainingTime <= 0) {
Slog.e(TAG, "Aborting stack trace dump (current firstPid=" + pid
+ "); deadline exceeded.");
- return firstPidStart >= 0 ? new Pair<>(firstPidStart, firstPidEnd) : null;
+ return firstPidEnd;
}
if (firstPid) {
- firstPidEnd = tf.length();
+ firstPidEnd = new File(tracesFile).length();
// Full latency dump
if (latencyTracker != null) {
appendtoANRFile(tracesFile,
@@ -3755,7 +3745,7 @@
if (remainingTime <= 0) {
Slog.e(TAG, "Aborting stack trace dump (current native pid=" + pid +
"); deadline exceeded.");
- return firstPidStart >= 0 ? new Pair<>(firstPidStart, firstPidEnd) : null;
+ return firstPidEnd;
}
if (DEBUG_ANR) {
@@ -3785,7 +3775,7 @@
if (remainingTime <= 0) {
Slog.e(TAG, "Aborting stack trace dump (current extra pid=" + pid +
"); deadline exceeded.");
- return firstPidStart >= 0 ? new Pair<>(firstPidStart, firstPidEnd) : null;
+ return firstPidEnd;
}
if (DEBUG_ANR) {
@@ -3800,7 +3790,7 @@
appendtoANRFile(tracesFile, "----- dumping ended at " + SystemClock.uptimeMillis() + "\n");
Slog.i(TAG, "Done dumping");
- return firstPidStart >= 0 ? new Pair<>(firstPidStart, firstPidEnd) : null;
+ return firstPidEnd;
}
@Override
@@ -13836,6 +13826,25 @@
}
}
+ // Apply permission policy around the use of specific broadcast options
+ void enforceBroadcastOptionPermissionsInternal(@Nullable Bundle options, int callingUid) {
+ if (options != null && callingUid != Process.SYSTEM_UID) {
+ if (options.containsKey(BroadcastOptions.KEY_ALARM_BROADCAST)) {
+ if (DEBUG_BROADCAST_LIGHT) {
+ Slog.w(TAG, "Non-system caller " + callingUid
+ + " may not flag broadcast as alarm");
+ }
+ throw new SecurityException(
+ "Non-system callers may not flag broadcasts as alarm");
+ }
+ if (options.containsKey(BroadcastOptions.KEY_INTERACTIVE_BROADCAST)) {
+ enforceCallingPermission(
+ android.Manifest.permission.BROADCAST_OPTION_INTERACTIVE,
+ "setInteractiveBroadcast");
+ }
+ }
+ }
+
@GuardedBy("this")
final int broadcastIntentLocked(ProcessRecord callerApp,
String callerPackage, String callerFeatureId, Intent intent, String resolvedType,
@@ -13865,6 +13874,29 @@
@Nullable IBinder backgroundActivityStartsToken,
@Nullable int[] broadcastAllowList,
@Nullable BiFunction<Integer, Bundle, Bundle> filterExtrasForReceiver) {
+ final int cookie = BroadcastQueue.traceBegin("broadcastIntentLockedTraced");
+ final int res = broadcastIntentLockedTraced(callerApp, callerPackage, callerFeatureId,
+ intent, resolvedType, resultToApp, resultTo, resultCode, resultData, resultExtras,
+ requiredPermissions, excludedPermissions, excludedPackages, appOp, bOptions,
+ ordered, sticky, callingPid, callingUid, realCallingUid, realCallingPid, userId,
+ allowBackgroundActivityStarts, backgroundActivityStartsToken, broadcastAllowList,
+ filterExtrasForReceiver);
+ BroadcastQueue.traceEnd(cookie);
+ return res;
+ }
+
+ @GuardedBy("this")
+ final int broadcastIntentLockedTraced(ProcessRecord callerApp, String callerPackage,
+ @Nullable String callerFeatureId, Intent intent, String resolvedType,
+ ProcessRecord resultToApp, IIntentReceiver resultTo, int resultCode, String resultData,
+ Bundle resultExtras, String[] requiredPermissions,
+ String[] excludedPermissions, String[] excludedPackages, int appOp, Bundle bOptions,
+ boolean ordered, boolean sticky, int callingPid, int callingUid,
+ int realCallingUid, int realCallingPid, int userId,
+ boolean allowBackgroundActivityStarts,
+ @Nullable IBinder backgroundActivityStartsToken,
+ @Nullable int[] broadcastAllowList,
+ @Nullable BiFunction<Integer, Bundle, Bundle> filterExtrasForReceiver) {
// Ensure all internal loopers are registered for idle checks
BroadcastLoopers.addMyLooper();
@@ -14416,6 +14448,7 @@
}
// Figure out who all will receive this broadcast.
+ final int cookie = BroadcastQueue.traceBegin("queryReceivers");
List receivers = null;
List<BroadcastFilter> registeredReceivers = null;
// Need to resolve the intent to interested receivers...
@@ -14446,6 +14479,7 @@
resolvedType, false /*defaultOnly*/, userId);
}
}
+ BroadcastQueue.traceEnd(cookie);
final boolean replacePending =
(intent.getFlags()&Intent.FLAG_RECEIVER_REPLACE_PENDING) != 0;
@@ -14703,19 +14737,8 @@
// We're delivering the result to the caller
final ProcessRecord resultToApp = callerApp;
- // Non-system callers can't declare that a broadcast is alarm-related.
- // The PendingIntent invocation case is handled in PendingIntentRecord.
- if (bOptions != null && callingUid != SYSTEM_UID) {
- if (bOptions.containsKey(BroadcastOptions.KEY_ALARM_BROADCAST)
- || bOptions.containsKey(BroadcastOptions.KEY_INTERACTIVE_BROADCAST)) {
- if (DEBUG_BROADCAST) {
- Slog.w(TAG, "Non-system caller " + callingUid
- + " may not flag broadcast as alarm or interactive");
- }
- throw new SecurityException(
- "Non-system callers may not flag broadcasts as alarm or interactive");
- }
- }
+ // Permission regimes around sender-supplied broadcast options.
+ enforceBroadcastOptionPermissionsInternal(bOptions, callingUid);
final long origId = Binder.clearCallingIdentity();
try {
@@ -16909,6 +16932,11 @@
return mEnableModernQueue;
}
+ @Override
+ public void enforceBroadcastOptionsPermissions(Bundle options, int callingUid) {
+ enforceBroadcastOptionPermissionsInternal(options, callingUid);
+ }
+
/**
* Returns package name by pid.
*/
diff --git a/services/core/java/com/android/server/am/BroadcastLoopers.java b/services/core/java/com/android/server/am/BroadcastLoopers.java
index bebb484..b828720 100644
--- a/services/core/java/com/android/server/am/BroadcastLoopers.java
+++ b/services/core/java/com/android/server/am/BroadcastLoopers.java
@@ -25,6 +25,8 @@
import android.util.ArraySet;
import android.util.Slog;
+import com.android.internal.annotations.GuardedBy;
+
import java.io.PrintWriter;
import java.util.Objects;
import java.util.concurrent.CountDownLatch;
@@ -37,6 +39,7 @@
public class BroadcastLoopers {
private static final String TAG = "BroadcastLoopers";
+ @GuardedBy("sLoopers")
private static final ArraySet<Looper> sLoopers = new ArraySet<>();
/**
diff --git a/services/core/java/com/android/server/am/BroadcastProcessQueue.java b/services/core/java/com/android/server/am/BroadcastProcessQueue.java
index f7d24e9..2e12309 100644
--- a/services/core/java/com/android/server/am/BroadcastProcessQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastProcessQueue.java
@@ -114,7 +114,14 @@
* dispatched to this process, in the same representation as
* {@link #mPending}.
*/
- private final ArrayDeque<SomeArgs> mPendingUrgent = new ArrayDeque<>();
+ private final ArrayDeque<SomeArgs> mPendingUrgent = new ArrayDeque<>(4);
+
+ /**
+ * Ordered collection of "offload" broadcasts that are waiting to be
+ * dispatched to this process, in the same representation as
+ * {@link #mPending}.
+ */
+ private final ArrayDeque<SomeArgs> mPendingOffload = new ArrayDeque<>(4);
/**
* Broadcast actively being dispatched to this process.
@@ -148,8 +155,7 @@
private boolean mActiveViaColdStart;
/**
- * Count of {@link #mPending} and {@link #mPendingUrgent} broadcasts of
- * these various flavors.
+ * Count of pending broadcasts of these various flavors.
*/
private int mCountForeground;
private int mCountOrdered;
@@ -177,6 +183,16 @@
this.uid = uid;
}
+ private @NonNull ArrayDeque<SomeArgs> getQueueForBroadcast(@NonNull BroadcastRecord record) {
+ if (record.isUrgent()) {
+ return mPendingUrgent;
+ } else if (record.isOffload()) {
+ return mPendingOffload;
+ } else {
+ return mPending;
+ }
+ }
+
/**
* Enqueue the given broadcast to be dispatched to this process at some
* future point in time. The target receiver is indicated by the given index
@@ -193,10 +209,12 @@
public void enqueueOrReplaceBroadcast(@NonNull BroadcastRecord record, int recordIndex,
int blockedUntilTerminalCount) {
if (record.isReplacePending()) {
- boolean didReplace = replaceBroadcastInQueue(mPending,
- record, recordIndex, blockedUntilTerminalCount)
- || replaceBroadcastInQueue(mPendingUrgent,
- record, recordIndex, blockedUntilTerminalCount);
+ boolean didReplace = replaceBroadcastInQueue(mPending, record, recordIndex,
+ blockedUntilTerminalCount)
+ || replaceBroadcastInQueue(mPendingUrgent, record, recordIndex,
+ blockedUntilTerminalCount)
+ || replaceBroadcastInQueue(mPendingOffload, record, recordIndex,
+ blockedUntilTerminalCount);
if (didReplace) {
return;
}
@@ -213,8 +231,7 @@
// issued ahead of others that are already pending, for example if this new
// broadcast is in a different delivery class or is tied to a direct user interaction
// with implicit responsiveness expectations.
- final ArrayDeque<SomeArgs> queue = record.isUrgent() ? mPendingUrgent : mPending;
- queue.addLast(newBroadcastArgs);
+ getQueueForBroadcast(record).addLast(newBroadcastArgs);
onBroadcastEnqueued(record, recordIndex);
}
@@ -227,7 +244,7 @@
* {@code false} otherwise.
*/
private boolean replaceBroadcastInQueue(@NonNull ArrayDeque<SomeArgs> queue,
- @NonNull BroadcastRecord record, int recordIndex, int blockedUntilTerminalCount) {
+ @NonNull BroadcastRecord record, int recordIndex, int blockedUntilTerminalCount) {
final Iterator<SomeArgs> it = queue.descendingIterator();
final Object receiver = record.receivers.get(recordIndex);
while (it.hasNext()) {
@@ -279,10 +296,13 @@
*/
public boolean forEachMatchingBroadcast(@NonNull BroadcastPredicate predicate,
@NonNull BroadcastConsumer consumer, boolean andRemove) {
- boolean didSomething = forEachMatchingBroadcastInQueue(mPending,
+ boolean didSomething = false;
+ didSomething |= forEachMatchingBroadcastInQueue(mPending,
predicate, consumer, andRemove);
didSomething |= forEachMatchingBroadcastInQueue(mPendingUrgent,
predicate, consumer, andRemove);
+ didSomething |= forEachMatchingBroadcastInQueue(mPendingOffload,
+ predicate, consumer, andRemove);
return didSomething;
}
@@ -516,7 +536,7 @@
}
public boolean isEmpty() {
- return mPending.isEmpty() && mPendingUrgent.isEmpty();
+ return mPending.isEmpty() && mPendingUrgent.isEmpty() && mPendingOffload.isEmpty();
}
public boolean isActive() {
@@ -537,6 +557,8 @@
return mPendingUrgent;
} else if (!mPending.isEmpty()) {
return mPending;
+ } else if (!mPendingOffload.isEmpty()) {
+ return mPendingOffload;
}
return null;
}
@@ -581,12 +603,15 @@
}
final SomeArgs next = mPending.peekFirst();
final SomeArgs nextUrgent = mPendingUrgent.peekFirst();
+ final SomeArgs nextOffload = mPendingOffload.peekFirst();
// Empty queue is past any barrier
- final boolean nextLater = next == null
+ final boolean nextLater = (next == null)
|| ((BroadcastRecord) next.arg1).enqueueTime > barrierTime;
- final boolean nextUrgentLater = nextUrgent == null
+ final boolean nextUrgentLater = (nextUrgent == null)
|| ((BroadcastRecord) nextUrgent.arg1).enqueueTime > barrierTime;
- return nextLater && nextUrgentLater;
+ final boolean nextOffloadLater = (nextOffload == null)
+ || ((BroadcastRecord) nextOffload.arg1).enqueueTime > barrierTime;
+ return nextLater && nextUrgentLater && nextOffloadLater;
}
public boolean isRunnable() {
@@ -726,8 +751,9 @@
// If we have too many broadcasts pending, bypass any delays that
// might have been applied above to aid draining
- if (mPending.size() + mPendingUrgent.size() >= constants.MAX_PENDING_BROADCASTS) {
- mRunnableAt = runnableAt;
+ if (mPending.size() + mPendingUrgent.size()
+ + mPendingOffload.size() >= constants.MAX_PENDING_BROADCASTS) {
+ mRunnableAt = Math.min(mRunnableAt, runnableAt);
mRunnableAtReason = REASON_MAX_PENDING;
}
} else {
@@ -845,23 +871,28 @@
pw.println();
pw.increaseIndent();
if (mActive != null) {
- dumpRecord(now, pw, mActive, mActiveIndex, mActiveBlockedUntilTerminalCount);
+ dumpRecord("ACTIVE", now, pw, mActive, mActiveIndex, mActiveBlockedUntilTerminalCount);
}
for (SomeArgs args : mPendingUrgent) {
final BroadcastRecord r = (BroadcastRecord) args.arg1;
- dumpRecord(now, pw, r, args.argi1, args.argi2);
+ dumpRecord("URGENT", now, pw, r, args.argi1, args.argi2);
}
for (SomeArgs args : mPending) {
final BroadcastRecord r = (BroadcastRecord) args.arg1;
- dumpRecord(now, pw, r, args.argi1, args.argi2);
+ dumpRecord(null, now, pw, r, args.argi1, args.argi2);
+ }
+ for (SomeArgs args : mPendingOffload) {
+ final BroadcastRecord r = (BroadcastRecord) args.arg1;
+ dumpRecord("OFFLOAD", now, pw, r, args.argi1, args.argi2);
}
pw.decreaseIndent();
pw.println();
}
@NeverCompile
- private void dumpRecord(@UptimeMillisLong long now, @NonNull IndentingPrintWriter pw,
- @NonNull BroadcastRecord record, int recordIndex, int blockedUntilTerminalCount) {
+ private void dumpRecord(@Nullable String flavor, @UptimeMillisLong long now,
+ @NonNull IndentingPrintWriter pw, @NonNull BroadcastRecord record, int recordIndex,
+ int blockedUntilTerminalCount) {
TimeUtils.formatDuration(record.enqueueTime, now, pw);
pw.print(' ');
pw.println(record.toShortString());
@@ -872,6 +903,10 @@
pw.print(" at ");
TimeUtils.formatDuration(record.scheduledTime[recordIndex], now, pw);
}
+ if (flavor != null) {
+ pw.print(' ');
+ pw.print(flavor);
+ }
final Object receiver = record.receivers.get(recordIndex);
if (receiver instanceof BroadcastFilter) {
final BroadcastFilter filter = (BroadcastFilter) receiver;
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index 1e172fc..e0fab2c 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -24,6 +24,7 @@
import android.os.Bundle;
import android.os.DropBoxManager;
import android.os.Handler;
+import android.os.Trace;
import android.util.Slog;
import android.util.proto.ProtoOutputStream;
@@ -76,6 +77,18 @@
}
}
+ static int traceBegin(@NonNull String methodName) {
+ final int cookie = methodName.hashCode();
+ Trace.asyncTraceForTrackBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
+ TAG, methodName, cookie);
+ return cookie;
+ }
+
+ static void traceEnd(int cookie) {
+ Trace.asyncTraceForTrackEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER,
+ TAG, cookie);
+ }
+
@Override
public String toString() {
return mQueueName;
diff --git a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
index 5750619..af2a97e 100644
--- a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
+++ b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
@@ -64,7 +64,6 @@
import android.os.Process;
import android.os.RemoteException;
import android.os.SystemClock;
-import android.os.Trace;
import android.os.UserHandle;
import android.text.format.DateUtils;
import android.util.IndentingPrintWriter;
@@ -144,14 +143,6 @@
mRunning = new BroadcastProcessQueue[mConstants.MAX_RUNNING_PROCESS_QUEUES];
}
- // TODO: add support for replacing pending broadcasts
- // TODO: add support for merging pending broadcasts
-
- // TODO: consider reordering foreground broadcasts within queue
-
- // TODO: pause queues when background services are running
- // TODO: pause queues when processes are frozen
-
/**
* Map from UID to per-process broadcast queues. If a UID hosts more than
* one process, each additional process is stored as a linked list using
@@ -222,12 +213,22 @@
private static final int MSG_DELIVERY_TIMEOUT_HARD = 3;
private static final int MSG_BG_ACTIVITY_START_TIMEOUT = 4;
private static final int MSG_CHECK_HEALTH = 5;
+ private static final int MSG_FINISH_RECEIVER = 6;
private void enqueueUpdateRunningList() {
mLocalHandler.removeMessages(MSG_UPDATE_RUNNING_LIST);
mLocalHandler.sendEmptyMessage(MSG_UPDATE_RUNNING_LIST);
}
+ private void enqueueFinishReceiver(@NonNull BroadcastProcessQueue queue,
+ @DeliveryState int deliveryState, @NonNull String reason) {
+ final SomeArgs args = SomeArgs.obtain();
+ args.arg1 = queue;
+ args.argi1 = deliveryState;
+ args.arg2 = reason;
+ mLocalHandler.sendMessage(Message.obtain(mLocalHandler, MSG_FINISH_RECEIVER, args));
+ }
+
private final Handler mLocalHandler;
private final Handler.Callback mLocalCallback = (msg) -> {
@@ -266,6 +267,17 @@
}
return true;
}
+ case MSG_FINISH_RECEIVER: {
+ synchronized (mService) {
+ final SomeArgs args = (SomeArgs) msg.obj;
+ final BroadcastProcessQueue queue = (BroadcastProcessQueue) args.arg1;
+ final int deliveryState = args.argi1;
+ final String reason = (String) args.arg2;
+ args.recycle();
+ finishReceiverLocked(queue, deliveryState, reason);
+ }
+ return true;
+ }
}
return false;
};
@@ -309,6 +321,7 @@
return;
}
+ final int cookie = traceBegin("updateRunnableList");
final boolean wantQueue = queue.isRunnable();
final boolean inQueue = (queue == mRunnableHead) || (queue.runnableAtPrev != null)
|| (queue.runnableAtNext != null);
@@ -335,6 +348,8 @@
if (queue.isEmpty() && !queue.isActive() && !queue.isProcessWarm()) {
removeProcessQueue(queue.processName, queue.uid);
}
+
+ traceEnd(cookie);
}
/**
@@ -349,7 +364,7 @@
int avail = mRunning.length - getRunningSize();
if (avail == 0) return;
- final int cookie = traceBegin(TAG, "updateRunningList");
+ final int cookie = traceBegin("updateRunningList");
final long now = SystemClock.uptimeMillis();
// If someone is waiting for a state, everything is runnable now
@@ -449,7 +464,7 @@
});
}
- traceEnd(TAG, cookie);
+ traceEnd(cookie);
}
@Override
@@ -516,7 +531,8 @@
if (queue != null) {
// If queue was running a broadcast, fail it
if (queue.isActive()) {
- finishReceiverLocked(queue, BroadcastRecord.DELIVERY_FAILURE);
+ finishReceiverLocked(queue, BroadcastRecord.DELIVERY_FAILURE,
+ "onApplicationCleanupLocked");
}
// Skip any pending registered receivers, since the old process
@@ -544,6 +560,7 @@
public void enqueueBroadcastLocked(@NonNull BroadcastRecord r) {
if (DEBUG_BROADCAST) logv("Enqueuing " + r + " for " + r.receivers.size() + " receivers");
+ final int cookie = traceBegin("enqueueBroadcast");
r.applySingletonPolicy(mService);
final IntentFilter removeMatchingFilter = (r.options != null)
@@ -613,6 +630,8 @@
if (r.receivers.isEmpty()) {
scheduleResultTo(r);
}
+
+ traceEnd(cookie);
}
private void applyDeliveryGroupPolicy(@NonNull BroadcastRecord r) {
@@ -668,7 +687,8 @@
// Ignore registered receivers from a previous PID
if (receiver instanceof BroadcastFilter) {
mRunningColdStart = null;
- finishReceiverLocked(queue, BroadcastRecord.DELIVERY_SKIPPED);
+ enqueueFinishReceiver(queue, BroadcastRecord.DELIVERY_SKIPPED,
+ "BroadcastFilter for cold app");
return;
}
@@ -690,7 +710,8 @@
hostingRecord, zygotePolicyFlags, allowWhileBooting, false);
if (queue.app == null) {
mRunningColdStart = null;
- finishReceiverLocked(queue, BroadcastRecord.DELIVERY_FAILURE);
+ enqueueFinishReceiver(queue, BroadcastRecord.DELIVERY_FAILURE,
+ "startProcessLocked failed");
return;
}
}
@@ -721,33 +742,37 @@
// If someone already finished this broadcast, finish immediately
final int oldDeliveryState = getDeliveryState(r, index);
if (isDeliveryStateTerminal(oldDeliveryState)) {
- finishReceiverLocked(queue, oldDeliveryState);
+ enqueueFinishReceiver(queue, oldDeliveryState, "already terminal state");
return;
}
// Consider additional cases where we'd want to finish immediately
if (app.isInFullBackup()) {
- finishReceiverLocked(queue, BroadcastRecord.DELIVERY_SKIPPED);
+ enqueueFinishReceiver(queue, BroadcastRecord.DELIVERY_SKIPPED, "isInFullBackup");
return;
}
if (mSkipPolicy.shouldSkip(r, receiver)) {
- finishReceiverLocked(queue, BroadcastRecord.DELIVERY_SKIPPED);
+ enqueueFinishReceiver(queue, BroadcastRecord.DELIVERY_SKIPPED, "mSkipPolicy");
return;
}
final Intent receiverIntent = r.getReceiverIntent(receiver);
if (receiverIntent == null) {
- finishReceiverLocked(queue, BroadcastRecord.DELIVERY_SKIPPED);
+ enqueueFinishReceiver(queue, BroadcastRecord.DELIVERY_SKIPPED, "isInFullBackup");
return;
}
// Ignore registered receivers from a previous PID
if ((receiver instanceof BroadcastFilter)
&& ((BroadcastFilter) receiver).receiverList.pid != app.getPid()) {
- finishReceiverLocked(queue, BroadcastRecord.DELIVERY_SKIPPED);
+ enqueueFinishReceiver(queue, BroadcastRecord.DELIVERY_SKIPPED,
+ "BroadcastFilter for mismatched PID");
return;
}
- if (mService.mProcessesReady && !r.timeoutExempt) {
+ // Skip ANR tracking early during boot, when requested, or when we
+ // immediately assume delivery success
+ final boolean assumeDelivered = (receiver instanceof BroadcastFilter) && !r.ordered;
+ if (mService.mProcessesReady && !r.timeoutExempt && !assumeDelivered) {
queue.lastCpuDelayTime = queue.app.getCpuDelayTime();
final long timeout = r.isForeground() ? mFgConstants.TIMEOUT : mBgConstants.TIMEOUT;
@@ -775,7 +800,8 @@
}
if (DEBUG_BROADCAST) logv("Scheduling " + r + " to warm " + app);
- setDeliveryState(queue, app, r, index, receiver, BroadcastRecord.DELIVERY_SCHEDULED);
+ setDeliveryState(queue, app, r, index, receiver, BroadcastRecord.DELIVERY_SCHEDULED,
+ "scheduleReceiverWarmLocked");
final IApplicationThread thread = app.getOnewayThread();
if (thread != null) {
@@ -789,8 +815,9 @@
// TODO: consider making registered receivers of unordered
// broadcasts report results to detect ANRs
- if (!r.ordered) {
- finishReceiverLocked(queue, BroadcastRecord.DELIVERY_DELIVERED);
+ if (assumeDelivered) {
+ enqueueFinishReceiver(queue, BroadcastRecord.DELIVERY_DELIVERED,
+ "assuming delivered");
}
} else {
notifyScheduleReceiver(app, r, (ResolveInfo) receiver);
@@ -804,10 +831,11 @@
logw(msg);
app.scheduleCrashLocked(msg, CannotDeliverBroadcastException.TYPE_ID, null);
app.setKilled(true);
- finishReceiverLocked(queue, BroadcastRecord.DELIVERY_FAILURE);
+ enqueueFinishReceiver(queue, BroadcastRecord.DELIVERY_FAILURE, "remote app");
}
} else {
- finishReceiverLocked(queue, BroadcastRecord.DELIVERY_FAILURE);
+ enqueueFinishReceiver(queue, BroadcastRecord.DELIVERY_FAILURE,
+ "missing IApplicationThread");
}
}
@@ -851,7 +879,8 @@
}
private void deliveryTimeoutHardLocked(@NonNull BroadcastProcessQueue queue) {
- finishReceiverLocked(queue, BroadcastRecord.DELIVERY_TIMEOUT);
+ finishReceiverLocked(queue, BroadcastRecord.DELIVERY_TIMEOUT,
+ "deliveryTimeoutHardLocked");
}
@Override
@@ -878,16 +907,17 @@
if (r.resultAbort) {
for (int i = r.terminalCount + 1; i < r.receivers.size(); i++) {
setDeliveryState(null, null, r, i, r.receivers.get(i),
- BroadcastRecord.DELIVERY_SKIPPED);
+ BroadcastRecord.DELIVERY_SKIPPED, "resultAbort");
}
}
}
- return finishReceiverLocked(queue, BroadcastRecord.DELIVERY_DELIVERED);
+ return finishReceiverLocked(queue, BroadcastRecord.DELIVERY_DELIVERED, "remote app");
}
private boolean finishReceiverLocked(@NonNull BroadcastProcessQueue queue,
- @DeliveryState int deliveryState) {
+ @DeliveryState int deliveryState, @NonNull String reason) {
+ final int cookie = traceBegin("finishReceiver");
checkState(queue.isActive(), "isActive");
final ProcessRecord app = queue.app;
@@ -895,7 +925,7 @@
final int index = queue.getActiveIndex();
final Object receiver = r.receivers.get(index);
- setDeliveryState(queue, app, r, index, receiver, deliveryState);
+ setDeliveryState(queue, app, r, index, receiver, deliveryState, reason);
if (deliveryState == BroadcastRecord.DELIVERY_TIMEOUT) {
r.anrCount++;
@@ -914,11 +944,12 @@
final boolean shouldRetire =
(queue.getActiveCountSinceIdle() >= mConstants.MAX_RUNNING_ACTIVE_BROADCASTS);
+ final boolean res;
if (queue.isRunnable() && queue.isProcessWarm() && !shouldRetire) {
// We're on a roll; move onto the next broadcast for this process
queue.makeActiveNextPending();
scheduleReceiverWarmLocked(queue);
- return true;
+ res = true;
} else {
// We've drained running broadcasts; maybe move back to runnable
queue.makeActiveIdle();
@@ -932,8 +963,10 @@
// Tell other OS components that app is not actively running, giving
// a chance to update OOM adjustment
notifyStoppedRunning(queue);
- return false;
+ res = false;
}
+ traceEnd(cookie);
+ return res;
}
/**
@@ -942,7 +975,8 @@
*/
private void setDeliveryState(@Nullable BroadcastProcessQueue queue,
@Nullable ProcessRecord app, @NonNull BroadcastRecord r, int index,
- @NonNull Object receiver, @DeliveryState int newDeliveryState) {
+ @NonNull Object receiver, @DeliveryState int newDeliveryState, String reason) {
+ final int cookie = traceBegin("setDeliveryState");
final int oldDeliveryState = getDeliveryState(r, index);
// Only apply state when we haven't already reached a terminal state;
@@ -970,7 +1004,7 @@
logw("Delivery state of " + r + " to " + receiver
+ " via " + app + " changed from "
+ deliveryStateToString(oldDeliveryState) + " to "
- + deliveryStateToString(newDeliveryState));
+ + deliveryStateToString(newDeliveryState) + " because " + reason);
}
r.terminalCount++;
@@ -1000,6 +1034,8 @@
enqueueUpdateRunningList();
}
}
+
+ traceEnd(cookie);
}
private @DeliveryState int getDeliveryState(@NonNull BroadcastRecord r, int index) {
@@ -1060,7 +1096,8 @@
* of it matching a predicate.
*/
private final BroadcastConsumer mBroadcastConsumerSkip = (r, i) -> {
- setDeliveryState(null, null, r, i, r.receivers.get(i), BroadcastRecord.DELIVERY_SKIPPED);
+ setDeliveryState(null, null, r, i, r.receivers.get(i), BroadcastRecord.DELIVERY_SKIPPED,
+ "mBroadcastConsumerSkip");
};
/**
@@ -1068,7 +1105,8 @@
* cancelled, usually as a result of it matching a predicate.
*/
private final BroadcastConsumer mBroadcastConsumerSkipAndCanceled = (r, i) -> {
- setDeliveryState(null, null, r, i, r.receivers.get(i), BroadcastRecord.DELIVERY_SKIPPED);
+ setDeliveryState(null, null, r, i, r.receivers.get(i), BroadcastRecord.DELIVERY_SKIPPED,
+ "mBroadcastConsumerSkipAndCanceled");
r.resultCode = Activity.RESULT_CANCELED;
r.resultData = null;
r.resultExtras = null;
@@ -1260,18 +1298,6 @@
}
}
- private int traceBegin(String trackName, String methodName) {
- final int cookie = methodName.hashCode();
- Trace.asyncTraceForTrackBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
- trackName, methodName, cookie);
- return cookie;
- }
-
- private void traceEnd(String trackName, int cookie) {
- Trace.asyncTraceForTrackEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER,
- trackName, cookie);
- }
-
private void updateWarmProcess(@NonNull BroadcastProcessQueue queue) {
if (!queue.isProcessWarm()) {
queue.setProcess(mService.getProcessRecordLocked(queue.processName, queue.uid));
diff --git a/services/core/java/com/android/server/am/BroadcastRecord.java b/services/core/java/com/android/server/am/BroadcastRecord.java
index 2a3c897..65f9b9b 100644
--- a/services/core/java/com/android/server/am/BroadcastRecord.java
+++ b/services/core/java/com/android/server/am/BroadcastRecord.java
@@ -617,6 +617,10 @@
return (intent.getFlags() & Intent.FLAG_RECEIVER_NO_ABORT) != 0;
}
+ boolean isOffload() {
+ return (intent.getFlags() & Intent.FLAG_RECEIVER_OFFLOAD) != 0;
+ }
+
/**
* Core policy determination about this broadcast's delivery prioritization
*/
diff --git a/services/core/java/com/android/server/am/BroadcastSkipPolicy.java b/services/core/java/com/android/server/am/BroadcastSkipPolicy.java
index 60fddf0..481ab17 100644
--- a/services/core/java/com/android/server/am/BroadcastSkipPolicy.java
+++ b/services/core/java/com/android/server/am/BroadcastSkipPolicy.java
@@ -21,6 +21,7 @@
import static com.android.server.am.BroadcastQueue.TAG;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.AppGlobals;
import android.app.AppOpsManager;
@@ -42,6 +43,8 @@
import com.android.internal.util.ArrayUtils;
+import java.util.Objects;
+
/**
* Policy logic that decides if delivery of a particular {@link BroadcastRecord}
* should be skipped for a given {@link ResolveInfo} or {@link BroadcastFilter}.
@@ -51,8 +54,8 @@
public class BroadcastSkipPolicy {
private final ActivityManagerService mService;
- public BroadcastSkipPolicy(ActivityManagerService service) {
- mService = service;
+ public BroadcastSkipPolicy(@NonNull ActivityManagerService service) {
+ mService = Objects.requireNonNull(service);
}
/**
@@ -60,18 +63,39 @@
* the given {@link BroadcastFilter} or {@link ResolveInfo}.
*/
public boolean shouldSkip(@NonNull BroadcastRecord r, @NonNull Object target) {
- if (target instanceof BroadcastFilter) {
- return shouldSkip(r, (BroadcastFilter) target);
+ final String msg = shouldSkipMessage(r, target);
+ if (msg != null) {
+ Slog.w(TAG, msg);
+ return true;
} else {
- return shouldSkip(r, (ResolveInfo) target);
+ return false;
+ }
+ }
+
+ /**
+ * Determine if the given {@link BroadcastRecord} is eligible to be sent to
+ * the given {@link BroadcastFilter} or {@link ResolveInfo}.
+ *
+ * @return message indicating why the argument should be skipped, otherwise
+ * {@code null} if it can proceed.
+ */
+ public @Nullable String shouldSkipMessage(@NonNull BroadcastRecord r, @NonNull Object target) {
+ if (target instanceof BroadcastFilter) {
+ return shouldSkipMessage(r, (BroadcastFilter) target);
+ } else {
+ return shouldSkipMessage(r, (ResolveInfo) target);
}
}
/**
* Determine if the given {@link BroadcastRecord} is eligible to be sent to
* the given {@link ResolveInfo}.
+ *
+ * @return message indicating why the argument should be skipped, otherwise
+ * {@code null} if it can proceed.
*/
- public boolean shouldSkip(@NonNull BroadcastRecord r, @NonNull ResolveInfo info) {
+ private @Nullable String shouldSkipMessage(@NonNull BroadcastRecord r,
+ @NonNull ResolveInfo info) {
final BroadcastOptions brOptions = r.options;
final ComponentName component = new ComponentName(
info.activityInfo.applicationInfo.packageName,
@@ -82,58 +106,52 @@
< brOptions.getMinManifestReceiverApiLevel() ||
info.activityInfo.applicationInfo.targetSdkVersion
> brOptions.getMaxManifestReceiverApiLevel())) {
- Slog.w(TAG, "Target SDK mismatch: receiver " + info.activityInfo
+ return "Target SDK mismatch: receiver " + info.activityInfo
+ " targets " + info.activityInfo.applicationInfo.targetSdkVersion
+ " but delivery restricted to ["
+ brOptions.getMinManifestReceiverApiLevel() + ", "
+ brOptions.getMaxManifestReceiverApiLevel()
- + "] broadcasting " + broadcastDescription(r, component));
- return true;
+ + "] broadcasting " + broadcastDescription(r, component);
}
if (brOptions != null &&
!brOptions.testRequireCompatChange(info.activityInfo.applicationInfo.uid)) {
- Slog.w(TAG, "Compat change filtered: broadcasting " + broadcastDescription(r, component)
+ return "Compat change filtered: broadcasting " + broadcastDescription(r, component)
+ " to uid " + info.activityInfo.applicationInfo.uid + " due to compat change "
- + r.options.getRequireCompatChangeId());
- return true;
+ + r.options.getRequireCompatChangeId();
}
if (!mService.validateAssociationAllowedLocked(r.callerPackage, r.callingUid,
component.getPackageName(), info.activityInfo.applicationInfo.uid)) {
- Slog.w(TAG, "Association not allowed: broadcasting "
- + broadcastDescription(r, component));
- return true;
+ return "Association not allowed: broadcasting "
+ + broadcastDescription(r, component);
}
if (!mService.mIntentFirewall.checkBroadcast(r.intent, r.callingUid,
r.callingPid, r.resolvedType, info.activityInfo.applicationInfo.uid)) {
- Slog.w(TAG, "Firewall blocked: broadcasting "
- + broadcastDescription(r, component));
- return true;
+ return "Firewall blocked: broadcasting "
+ + broadcastDescription(r, component);
}
int perm = checkComponentPermission(info.activityInfo.permission,
r.callingPid, r.callingUid, info.activityInfo.applicationInfo.uid,
info.activityInfo.exported);
if (perm != PackageManager.PERMISSION_GRANTED) {
if (!info.activityInfo.exported) {
- Slog.w(TAG, "Permission Denial: broadcasting "
+ return "Permission Denial: broadcasting "
+ broadcastDescription(r, component)
- + " is not exported from uid " + info.activityInfo.applicationInfo.uid);
+ + " is not exported from uid " + info.activityInfo.applicationInfo.uid;
} else {
- Slog.w(TAG, "Permission Denial: broadcasting "
+ return "Permission Denial: broadcasting "
+ broadcastDescription(r, component)
- + " requires " + info.activityInfo.permission);
+ + " requires " + info.activityInfo.permission;
}
- return true;
} else if (info.activityInfo.permission != null) {
final int opCode = AppOpsManager.permissionToOpCode(info.activityInfo.permission);
if (opCode != AppOpsManager.OP_NONE && mService.getAppOpsManager().noteOpNoThrow(opCode,
r.callingUid, r.callerPackage, r.callerFeatureId,
"Broadcast delivered to " + info.activityInfo.name)
!= AppOpsManager.MODE_ALLOWED) {
- Slog.w(TAG, "Appop Denial: broadcasting "
+ return "Appop Denial: broadcasting "
+ broadcastDescription(r, component)
+ " requires appop " + AppOpsManager.permissionToOp(
- info.activityInfo.permission));
- return true;
+ info.activityInfo.permission);
}
}
@@ -142,38 +160,34 @@
android.Manifest.permission.INTERACT_ACROSS_USERS,
info.activityInfo.applicationInfo.uid)
!= PackageManager.PERMISSION_GRANTED) {
- Slog.w(TAG, "Permission Denial: Receiver " + component.flattenToShortString()
+ return "Permission Denial: Receiver " + component.flattenToShortString()
+ " requests FLAG_SINGLE_USER, but app does not hold "
- + android.Manifest.permission.INTERACT_ACROSS_USERS);
- return true;
+ + android.Manifest.permission.INTERACT_ACROSS_USERS;
}
}
if (info.activityInfo.applicationInfo.isInstantApp()
&& r.callingUid != info.activityInfo.applicationInfo.uid) {
- Slog.w(TAG, "Instant App Denial: receiving "
+ return "Instant App Denial: receiving "
+ r.intent
+ " to " + component.flattenToShortString()
+ " due to sender " + r.callerPackage
+ " (uid " + r.callingUid + ")"
- + " Instant Apps do not support manifest receivers");
- return true;
+ + " Instant Apps do not support manifest receivers";
}
if (r.callerInstantApp
&& (info.activityInfo.flags & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) == 0
&& r.callingUid != info.activityInfo.applicationInfo.uid) {
- Slog.w(TAG, "Instant App Denial: receiving "
+ return "Instant App Denial: receiving "
+ r.intent
+ " to " + component.flattenToShortString()
+ " requires receiver have visibleToInstantApps set"
+ " due to sender " + r.callerPackage
- + " (uid " + r.callingUid + ")");
- return true;
+ + " (uid " + r.callingUid + ")";
}
if (r.curApp != null && r.curApp.mErrorState.isCrashing()) {
// If the target process is crashing, just skip it.
- Slog.w(TAG, "Skipping deliver ordered [" + r.queue.toString() + "] " + r
- + " to " + r.curApp + ": process crashing");
- return true;
+ return "Skipping deliver ordered [" + r.queue.toString() + "] " + r
+ + " to " + r.curApp + ": process crashing";
}
boolean isAvailable = false;
@@ -183,15 +197,13 @@
UserHandle.getUserId(info.activityInfo.applicationInfo.uid));
} catch (Exception e) {
// all such failures mean we skip this receiver
- Slog.w(TAG, "Exception getting recipient info for "
- + info.activityInfo.packageName, e);
+ return "Exception getting recipient info for "
+ + info.activityInfo.packageName;
}
if (!isAvailable) {
- Slog.w(TAG,
- "Skipping delivery to " + info.activityInfo.packageName + " / "
+ return "Skipping delivery to " + info.activityInfo.packageName + " / "
+ info.activityInfo.applicationInfo.uid
- + " : package no longer available");
- return true;
+ + " : package no longer available";
}
// If permissions need a review before any of the app components can run, we drop
@@ -201,10 +213,8 @@
if (!requestStartTargetPermissionsReviewIfNeededLocked(r,
info.activityInfo.packageName, UserHandle.getUserId(
info.activityInfo.applicationInfo.uid))) {
- Slog.w(TAG,
- "Skipping delivery: permission review required for "
- + broadcastDescription(r, component));
- return true;
+ return "Skipping delivery: permission review required for "
+ + broadcastDescription(r, component);
}
final int allowed = mService.getAppStartModeLOSP(
@@ -216,10 +226,9 @@
// to it and the app is in a state that should not receive it
// (depending on how getAppStartModeLOSP has determined that).
if (allowed == ActivityManager.APP_START_MODE_DISABLED) {
- Slog.w(TAG, "Background execution disabled: receiving "
+ return "Background execution disabled: receiving "
+ r.intent + " to "
- + component.flattenToShortString());
- return true;
+ + component.flattenToShortString();
} else if (((r.intent.getFlags()&Intent.FLAG_RECEIVER_EXCLUDE_BACKGROUND) != 0)
|| (r.intent.getComponent() == null
&& r.intent.getPackage() == null
@@ -228,10 +237,9 @@
&& !isSignaturePerm(r.requiredPermissions))) {
mService.addBackgroundCheckViolationLocked(r.intent.getAction(),
component.getPackageName());
- Slog.w(TAG, "Background execution not allowed: receiving "
+ return "Background execution not allowed: receiving "
+ r.intent + " to "
- + component.flattenToShortString());
- return true;
+ + component.flattenToShortString();
}
}
@@ -239,10 +247,8 @@
&& !mService.mUserController
.isUserRunning(UserHandle.getUserId(info.activityInfo.applicationInfo.uid),
0 /* flags */)) {
- Slog.w(TAG,
- "Skipping delivery to " + info.activityInfo.packageName + " / "
- + info.activityInfo.applicationInfo.uid + " : user is not running");
- return true;
+ return "Skipping delivery to " + info.activityInfo.packageName + " / "
+ + info.activityInfo.applicationInfo.uid + " : user is not running";
}
if (r.excludedPermissions != null && r.excludedPermissions.length > 0) {
@@ -268,13 +274,15 @@
info.activityInfo.applicationInfo.uid,
info.activityInfo.packageName)
== AppOpsManager.MODE_ALLOWED)) {
- return true;
+ return "Skipping delivery to " + info.activityInfo.packageName
+ + " due to excluded permission " + excludedPermission;
}
} else {
// When there is no app op associated with the permission,
// skip when permission is granted.
if (perm == PackageManager.PERMISSION_GRANTED) {
- return true;
+ return "Skipping delivery to " + info.activityInfo.packageName
+ + " due to excluded permission " + excludedPermission;
}
}
}
@@ -283,13 +291,12 @@
// Check that the receiver does *not* belong to any of the excluded packages
if (r.excludedPackages != null && r.excludedPackages.length > 0) {
if (ArrayUtils.contains(r.excludedPackages, component.getPackageName())) {
- Slog.w(TAG, "Skipping delivery of excluded package "
+ return "Skipping delivery of excluded package "
+ r.intent + " to "
+ component.flattenToShortString()
+ " excludes package " + component.getPackageName()
+ " due to sender " + r.callerPackage
- + " (uid " + r.callingUid + ")");
- return true;
+ + " (uid " + r.callingUid + ")";
}
}
@@ -307,95 +314,94 @@
perm = PackageManager.PERMISSION_DENIED;
}
if (perm != PackageManager.PERMISSION_GRANTED) {
- Slog.w(TAG, "Permission Denial: receiving "
+ return "Permission Denial: receiving "
+ r.intent + " to "
+ component.flattenToShortString()
+ " requires " + requiredPermission
+ " due to sender " + r.callerPackage
- + " (uid " + r.callingUid + ")");
- return true;
+ + " (uid " + r.callingUid + ")";
}
int appOp = AppOpsManager.permissionToOpCode(requiredPermission);
if (appOp != AppOpsManager.OP_NONE && appOp != r.appOp) {
if (!noteOpForManifestReceiver(appOp, r, info, component)) {
- return true;
+ return "Skipping delivery to " + info.activityInfo.packageName
+ + " due to required appop " + appOp;
}
}
}
}
if (r.appOp != AppOpsManager.OP_NONE) {
if (!noteOpForManifestReceiver(r.appOp, r, info, component)) {
- return true;
+ return "Skipping delivery to " + info.activityInfo.packageName
+ + " due to required appop " + r.appOp;
}
}
- return false;
+ return null;
}
/**
* Determine if the given {@link BroadcastRecord} is eligible to be sent to
* the given {@link BroadcastFilter}.
+ *
+ * @return message indicating why the argument should be skipped, otherwise
+ * {@code null} if it can proceed.
*/
- public boolean shouldSkip(@NonNull BroadcastRecord r, @NonNull BroadcastFilter filter) {
+ private @Nullable String shouldSkipMessage(@NonNull BroadcastRecord r,
+ @NonNull BroadcastFilter filter) {
if (r.options != null && !r.options.testRequireCompatChange(filter.owningUid)) {
- Slog.w(TAG, "Compat change filtered: broadcasting " + r.intent.toString()
+ return "Compat change filtered: broadcasting " + r.intent.toString()
+ " to uid " + filter.owningUid + " due to compat change "
- + r.options.getRequireCompatChangeId());
- return true;
+ + r.options.getRequireCompatChangeId();
}
if (!mService.validateAssociationAllowedLocked(r.callerPackage, r.callingUid,
filter.packageName, filter.owningUid)) {
- Slog.w(TAG, "Association not allowed: broadcasting "
+ return "Association not allowed: broadcasting "
+ r.intent.toString()
+ " from " + r.callerPackage + " (pid=" + r.callingPid
+ ", uid=" + r.callingUid + ") to " + filter.packageName + " through "
- + filter);
- return true;
+ + filter;
}
if (!mService.mIntentFirewall.checkBroadcast(r.intent, r.callingUid,
r.callingPid, r.resolvedType, filter.receiverList.uid)) {
- Slog.w(TAG, "Firewall blocked: broadcasting "
+ return "Firewall blocked: broadcasting "
+ r.intent.toString()
+ " from " + r.callerPackage + " (pid=" + r.callingPid
+ ", uid=" + r.callingUid + ") to " + filter.packageName + " through "
- + filter);
- return true;
+ + filter;
}
// Check that the sender has permission to send to this receiver
if (filter.requiredPermission != null) {
int perm = checkComponentPermission(filter.requiredPermission,
r.callingPid, r.callingUid, -1, true);
if (perm != PackageManager.PERMISSION_GRANTED) {
- Slog.w(TAG, "Permission Denial: broadcasting "
+ return "Permission Denial: broadcasting "
+ r.intent.toString()
+ " from " + r.callerPackage + " (pid="
+ r.callingPid + ", uid=" + r.callingUid + ")"
+ " requires " + filter.requiredPermission
- + " due to registered receiver " + filter);
- return true;
+ + " due to registered receiver " + filter;
} else {
final int opCode = AppOpsManager.permissionToOpCode(filter.requiredPermission);
if (opCode != AppOpsManager.OP_NONE
&& mService.getAppOpsManager().noteOpNoThrow(opCode, r.callingUid,
r.callerPackage, r.callerFeatureId, "Broadcast sent to protected receiver")
!= AppOpsManager.MODE_ALLOWED) {
- Slog.w(TAG, "Appop Denial: broadcasting "
+ return "Appop Denial: broadcasting "
+ r.intent.toString()
+ " from " + r.callerPackage + " (pid="
+ r.callingPid + ", uid=" + r.callingUid + ")"
+ " requires appop " + AppOpsManager.permissionToOp(
filter.requiredPermission)
- + " due to registered receiver " + filter);
- return true;
+ + " due to registered receiver " + filter;
}
}
}
if ((filter.receiverList.app == null || filter.receiverList.app.isKilled()
|| filter.receiverList.app.mErrorState.isCrashing())) {
- Slog.w(TAG, "Skipping deliver [" + r.queue.toString() + "] " + r
- + " to " + filter.receiverList + ": process gone or crashing");
- return true;
+ return "Skipping deliver [" + r.queue.toString() + "] " + r
+ + " to " + filter.receiverList + ": process gone or crashing";
}
// Ensure that broadcasts are only sent to other Instant Apps if they are marked as
@@ -405,28 +411,26 @@
if (!visibleToInstantApps && filter.instantApp
&& filter.receiverList.uid != r.callingUid) {
- Slog.w(TAG, "Instant App Denial: receiving "
+ return "Instant App Denial: receiving "
+ r.intent.toString()
+ " to " + filter.receiverList.app
+ " (pid=" + filter.receiverList.pid
+ ", uid=" + filter.receiverList.uid + ")"
+ " due to sender " + r.callerPackage
+ " (uid " + r.callingUid + ")"
- + " not specifying FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS");
- return true;
+ + " not specifying FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS";
}
if (!filter.visibleToInstantApp && r.callerInstantApp
&& filter.receiverList.uid != r.callingUid) {
- Slog.w(TAG, "Instant App Denial: receiving "
+ return "Instant App Denial: receiving "
+ r.intent.toString()
+ " to " + filter.receiverList.app
+ " (pid=" + filter.receiverList.pid
+ ", uid=" + filter.receiverList.uid + ")"
+ " requires receiver be visible to instant apps"
+ " due to sender " + r.callerPackage
- + " (uid " + r.callingUid + ")");
- return true;
+ + " (uid " + r.callingUid + ")";
}
// Check that the receiver has the required permission(s) to receive this broadcast.
@@ -436,15 +440,14 @@
int perm = checkComponentPermission(requiredPermission,
filter.receiverList.pid, filter.receiverList.uid, -1, true);
if (perm != PackageManager.PERMISSION_GRANTED) {
- Slog.w(TAG, "Permission Denial: receiving "
+ return "Permission Denial: receiving "
+ r.intent.toString()
+ " to " + filter.receiverList.app
+ " (pid=" + filter.receiverList.pid
+ ", uid=" + filter.receiverList.uid + ")"
+ " requires " + requiredPermission
+ " due to sender " + r.callerPackage
- + " (uid " + r.callingUid + ")");
- return true;
+ + " (uid " + r.callingUid + ")";
}
int appOp = AppOpsManager.permissionToOpCode(requiredPermission);
if (appOp != AppOpsManager.OP_NONE && appOp != r.appOp
@@ -452,7 +455,7 @@
filter.receiverList.uid, filter.packageName, filter.featureId,
"Broadcast delivered to registered receiver " + filter.receiverId)
!= AppOpsManager.MODE_ALLOWED) {
- Slog.w(TAG, "Appop Denial: receiving "
+ return "Appop Denial: receiving "
+ r.intent.toString()
+ " to " + filter.receiverList.app
+ " (pid=" + filter.receiverList.pid
@@ -460,8 +463,7 @@
+ " requires appop " + AppOpsManager.permissionToOp(
requiredPermission)
+ " due to sender " + r.callerPackage
- + " (uid " + r.callingUid + ")");
- return true;
+ + " (uid " + r.callingUid + ")";
}
}
}
@@ -469,14 +471,13 @@
int perm = checkComponentPermission(null,
filter.receiverList.pid, filter.receiverList.uid, -1, true);
if (perm != PackageManager.PERMISSION_GRANTED) {
- Slog.w(TAG, "Permission Denial: security check failed when receiving "
+ return "Permission Denial: security check failed when receiving "
+ r.intent.toString()
+ " to " + filter.receiverList.app
+ " (pid=" + filter.receiverList.pid
+ ", uid=" + filter.receiverList.uid + ")"
+ " due to sender " + r.callerPackage
- + " (uid " + r.callingUid + ")");
- return true;
+ + " (uid " + r.callingUid + ")";
}
}
// Check that the receiver does *not* have any excluded permissions
@@ -496,7 +497,7 @@
filter.receiverList.uid,
filter.packageName)
== AppOpsManager.MODE_ALLOWED)) {
- Slog.w(TAG, "Appop Denial: receiving "
+ return "Appop Denial: receiving "
+ r.intent.toString()
+ " to " + filter.receiverList.app
+ " (pid=" + filter.receiverList.pid
@@ -504,22 +505,20 @@
+ " excludes appop " + AppOpsManager.permissionToOp(
excludedPermission)
+ " due to sender " + r.callerPackage
- + " (uid " + r.callingUid + ")");
- return true;
+ + " (uid " + r.callingUid + ")";
}
} else {
// When there is no app op associated with the permission,
// skip when permission is granted.
if (perm == PackageManager.PERMISSION_GRANTED) {
- Slog.w(TAG, "Permission Denial: receiving "
+ return "Permission Denial: receiving "
+ r.intent.toString()
+ " to " + filter.receiverList.app
+ " (pid=" + filter.receiverList.pid
+ ", uid=" + filter.receiverList.uid + ")"
+ " excludes " + excludedPermission
+ " due to sender " + r.callerPackage
- + " (uid " + r.callingUid + ")");
- return true;
+ + " (uid " + r.callingUid + ")";
}
}
}
@@ -528,15 +527,14 @@
// Check that the receiver does *not* belong to any of the excluded packages
if (r.excludedPackages != null && r.excludedPackages.length > 0) {
if (ArrayUtils.contains(r.excludedPackages, filter.packageName)) {
- Slog.w(TAG, "Skipping delivery of excluded package "
+ return "Skipping delivery of excluded package "
+ r.intent.toString()
+ " to " + filter.receiverList.app
+ " (pid=" + filter.receiverList.pid
+ ", uid=" + filter.receiverList.uid + ")"
+ " excludes package " + filter.packageName
+ " due to sender " + r.callerPackage
- + " (uid " + r.callingUid + ")");
- return true;
+ + " (uid " + r.callingUid + ")";
}
}
@@ -546,15 +544,14 @@
filter.receiverList.uid, filter.packageName, filter.featureId,
"Broadcast delivered to registered receiver " + filter.receiverId)
!= AppOpsManager.MODE_ALLOWED) {
- Slog.w(TAG, "Appop Denial: receiving "
+ return "Appop Denial: receiving "
+ r.intent.toString()
+ " to " + filter.receiverList.app
+ " (pid=" + filter.receiverList.pid
+ ", uid=" + filter.receiverList.uid + ")"
+ " requires appop " + AppOpsManager.opToName(r.appOp)
+ " due to sender " + r.callerPackage
- + " (uid " + r.callingUid + ")");
- return true;
+ + " (uid " + r.callingUid + ")";
}
// Ensure that broadcasts are only sent to other apps if they are explicitly marked as
@@ -562,15 +559,14 @@
if (!filter.exported && checkComponentPermission(null, r.callingPid,
r.callingUid, filter.receiverList.uid, filter.exported)
!= PackageManager.PERMISSION_GRANTED) {
- Slog.w(TAG, "Exported Denial: sending "
+ return "Exported Denial: sending "
+ r.intent.toString()
+ ", action: " + r.intent.getAction()
+ " from " + r.callerPackage
+ " (uid=" + r.callingUid + ")"
+ " due to receiver " + filter.receiverList.app
+ " (uid " + filter.receiverList.uid + ")"
- + " not specifying RECEIVER_EXPORTED");
- return true;
+ + " not specifying RECEIVER_EXPORTED";
}
// If permissions need a review before any of the app components can run, we drop
@@ -579,10 +575,10 @@
// broadcast.
if (!requestStartTargetPermissionsReviewIfNeededLocked(r, filter.packageName,
filter.owningUserId)) {
- return true;
+ return "Skipping delivery to " + filter.packageName + " due to permissions review";
}
- return false;
+ return null;
}
private static String broadcastDescription(BroadcastRecord r, ComponentName component) {
diff --git a/services/core/java/com/android/server/am/PendingIntentRecord.java b/services/core/java/com/android/server/am/PendingIntentRecord.java
index 14a1697..3f5f3bc 100644
--- a/services/core/java/com/android/server/am/PendingIntentRecord.java
+++ b/services/core/java/com/android/server/am/PendingIntentRecord.java
@@ -18,7 +18,6 @@
import static android.app.ActivityManager.START_SUCCESS;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BROADCAST_LIGHT;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
@@ -36,7 +35,6 @@
import android.os.IBinder;
import android.os.PowerWhitelistManager;
import android.os.PowerWhitelistManager.ReasonCode;
-import android.os.Process;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.TransactionTooLargeException;
@@ -441,17 +439,8 @@
// 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.
- if (options != null && callingUid != Process.SYSTEM_UID
- && key.type == ActivityManager.INTENT_SENDER_BROADCAST) {
- if (options.containsKey(BroadcastOptions.KEY_ALARM_BROADCAST)
- || options.containsKey(BroadcastOptions.KEY_INTERACTIVE_BROADCAST)) {
- if (DEBUG_BROADCAST_LIGHT) {
- Slog.w(TAG, "Non-system caller " + callingUid
- + " may not flag broadcast as alarm or interactive");
- }
- throw new SecurityException(
- "Non-system callers may not flag broadcasts as alarm or interactive");
- }
+ if (key.type == ActivityManager.INTENT_SENDER_BROADCAST) {
+ controller.mAmInternal.enforceBroadcastOptionsPermissions(options, callingUid);
}
final long origId = Binder.clearCallingIdentity();
diff --git a/services/core/java/com/android/server/am/ProcessErrorStateRecord.java b/services/core/java/com/android/server/am/ProcessErrorStateRecord.java
index 71d39964..f461f3d 100644
--- a/services/core/java/com/android/server/am/ProcessErrorStateRecord.java
+++ b/services/core/java/com/android/server/am/ProcessErrorStateRecord.java
@@ -62,6 +62,8 @@
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.UUID;
+import java.util.concurrent.atomic.AtomicLong;
+
/**
* The error state of the process, such as if it's crashing/ANR etc.
*/
@@ -458,10 +460,10 @@
// avoid spending 1/2 second collecting stats to rank lastPids.
StringWriter tracesFileException = new StringWriter();
// To hold the start and end offset to the ANR trace file respectively.
- final long[] offsets = new long[2];
+ final AtomicLong firstPidEndOffset = new AtomicLong(-1);
File tracesFile = ActivityManagerService.dumpStackTraces(firstPids,
isSilentAnr ? null : processCpuTracker, isSilentAnr ? null : lastPids,
- nativePids, tracesFileException, offsets, annotation, criticalEventLog,
+ nativePids, tracesFileException, firstPidEndOffset, annotation, criticalEventLog,
latencyTracker);
if (isMonitorCpuUsage()) {
@@ -478,10 +480,14 @@
if (tracesFile == null) {
// There is no trace file, so dump (only) the alleged culprit's threads to the log
Process.sendSignal(pid, Process.SIGNAL_QUIT);
- } else if (offsets[1] > 0) {
+ } else if (firstPidEndOffset.get() > 0) {
// We've dumped into the trace file successfully
+ // We pass the start and end offsets of the first section of
+ // the ANR file (the headers and first process dump)
+ final long startOffset = 0L;
+ final long endOffset = firstPidEndOffset.get();
mService.mProcessList.mAppExitInfoTracker.scheduleLogAnrTrace(
- pid, mApp.uid, mApp.getPackageList(), tracesFile, offsets[0], offsets[1]);
+ pid, mApp.uid, mApp.getPackageList(), tracesFile, startOffset, endOffset);
}
// Check if package is still being loaded
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 82d239f..8d3890c 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -2185,8 +2185,6 @@
mHandler.sendMessage(mHandler.obtainMessage(COMPLETE_USER_SWITCH_MSG, newUserId, 0));
uss.switching = false;
- mHandler.removeMessages(REPORT_USER_SWITCH_COMPLETE_MSG);
- mHandler.sendMessage(mHandler.obtainMessage(REPORT_USER_SWITCH_COMPLETE_MSG, newUserId, 0));
stopGuestOrEphemeralUserIfBackground(oldUserId);
stopUserOnSwitchIfEnforced(oldUserId);
if (oldUserId == UserHandle.USER_SYSTEM) {
@@ -2200,21 +2198,22 @@
@VisibleForTesting
void completeUserSwitch(int newUserId) {
- if (isUserSwitchUiEnabled()) {
- // If there is no challenge set, dismiss the keyguard right away
- if (!mInjector.getKeyguardManager().isDeviceSecure(newUserId)) {
- // Wait until the keyguard is dismissed to unfreeze
- mInjector.dismissKeyguard(
- new Runnable() {
- public void run() {
- unfreezeScreen();
- }
- },
- "User Switch");
- return;
- } else {
+ final boolean isUserSwitchUiEnabled = isUserSwitchUiEnabled();
+ final Runnable runnable = () -> {
+ if (isUserSwitchUiEnabled) {
unfreezeScreen();
}
+ mHandler.removeMessages(REPORT_USER_SWITCH_COMPLETE_MSG);
+ mHandler.sendMessage(mHandler.obtainMessage(
+ REPORT_USER_SWITCH_COMPLETE_MSG, newUserId, 0));
+ };
+
+ // If there is no challenge set, dismiss the keyguard right away
+ if (isUserSwitchUiEnabled && !mInjector.getKeyguardManager().isDeviceSecure(newUserId)) {
+ // Wait until the keyguard is dismissed to unfreeze
+ mInjector.dismissKeyguard(runnable, "User Switch");
+ } else {
+ runnable.run();
}
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java b/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java
index 1d90954..055c63d 100644
--- a/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java
@@ -38,8 +38,7 @@
* Abstract {@link HalClientMonitor} subclass that operations eligible/interested in acquisition
* messages should extend.
*/
-public abstract class AcquisitionClient<T> extends HalClientMonitor<T> implements Interruptable,
- ErrorConsumer {
+public abstract class AcquisitionClient<T> extends HalClientMonitor<T> implements ErrorConsumer {
private static final String TAG = "Biometrics/AcquisitionClient";
@@ -217,4 +216,9 @@
HARDWARE_FEEDBACK_VIBRATION_ATTRIBUTES);
}
}
+
+ @Override
+ public boolean isInterruptable() {
+ return true;
+ }
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/BaseClientMonitor.java b/services/core/java/com/android/server/biometrics/sensors/BaseClientMonitor.java
index da7781a..0216e49 100644
--- a/services/core/java/com/android/server/biometrics/sensors/BaseClientMonitor.java
+++ b/services/core/java/com/android/server/biometrics/sensors/BaseClientMonitor.java
@@ -193,9 +193,9 @@
}
// If the current client dies we should cancel the current operation.
- if (this instanceof Interruptable) {
+ if (this.isInterruptable()) {
Slog.e(TAG, "Binder died, cancelling client");
- ((Interruptable) this).cancel();
+ this.cancel();
}
mToken = null;
if (clearListener) {
@@ -320,4 +320,12 @@
}
callback.onClientFinished(this, true /* success */);
}
+
+ /**
+ * Checks if other client monitor can interrupt current client monitor
+ * @return if current client can be interrupted
+ */
+ public boolean isInterruptable() {
+ return false;
+ }
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/BiometricSchedulerOperation.java b/services/core/java/com/android/server/biometrics/sensors/BiometricSchedulerOperation.java
index dacec38..4825f1d 100644
--- a/services/core/java/com/android/server/biometrics/sensors/BiometricSchedulerOperation.java
+++ b/services/core/java/com/android/server/biometrics/sensors/BiometricSchedulerOperation.java
@@ -46,7 +46,7 @@
/**
* The operation is added to the list of pending operations, but a subsequent operation
- * has been added. This state only applies to {@link Interruptable} operations. When this
+ * has been added. This state only applies to interruptable operations. When this
* operation reaches the head of the queue, it will send ERROR_CANCELED and finish.
*/
protected static final int STATE_WAITING_IN_QUEUE_CANCELING = 1;
@@ -347,9 +347,9 @@
return mClientMonitor == clientMonitor;
}
- /** If this operation is {@link Interruptable}. */
+ /** If this operation is interruptable. */
public boolean isInterruptable() {
- return mClientMonitor instanceof Interruptable;
+ return mClientMonitor.isInterruptable();
}
private boolean isHalOperation() {
diff --git a/services/core/java/com/android/server/biometrics/sensors/Interruptable.java b/services/core/java/com/android/server/biometrics/sensors/Interruptable.java
deleted file mode 100644
index 4f645ef..0000000
--- a/services/core/java/com/android/server/biometrics/sensors/Interruptable.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.biometrics.sensors;
-
-import android.annotation.NonNull;
-
-/**
- * Interface that {@link BaseClientMonitor} subclasses eligible for cancellation should implement.
- */
-public interface Interruptable {
- /**
- * Requests to end the ClientMonitor's lifecycle.
- */
- void cancel();
-
- /**
- * Notifies the client that it needs to finish before
- * {@link BaseClientMonitor#start(ClientMonitorCallback)} was invoked. This usually happens
- * if the client is still waiting in the pending queue and got notified that a subsequent
- * operation is preempting it.
- *
- * This method must invoke
- * {@link ClientMonitorCallback#onClientFinished(BaseClientMonitor, boolean)} on the
- * given callback (with success).
- *
- * @param callback invoked when the operation is completed.
- */
- void cancelWithoutStarting(@NonNull ClientMonitorCallback callback);
-}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java
index 800d4b8..0f5cdc3 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/Sensor.java
@@ -59,7 +59,6 @@
import com.android.server.biometrics.sensors.BiometricScheduler;
import com.android.server.biometrics.sensors.EnumerateConsumer;
import com.android.server.biometrics.sensors.ErrorConsumer;
-import com.android.server.biometrics.sensors.Interruptable;
import com.android.server.biometrics.sensors.LockoutCache;
import com.android.server.biometrics.sensors.LockoutConsumer;
import com.android.server.biometrics.sensors.LockoutResetDispatcher;
@@ -638,7 +637,7 @@
public void onBinderDied() {
final BaseClientMonitor client = mScheduler.getCurrentClient();
- if (client instanceof Interruptable) {
+ if (client.isInterruptable()) {
Slog.e(mTag, "Sending ERROR_HW_UNAVAILABLE for client: " + client);
final ErrorConsumer errorConsumer = (ErrorConsumer) client;
errorConsumer.onError(FaceManager.FACE_ERROR_HW_UNAVAILABLE,
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index 45b0f0a6..c671a2c 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -28,6 +28,7 @@
import static android.os.PowerWhitelistManager.REASON_VPN;
import static android.os.UserHandle.PER_USER_RANGE;
+import static com.android.net.module.util.NetworkStackConstants.IPV6_MIN_MTU;
import static com.android.server.vcn.util.PersistableBundleUtils.STRING_DESERIALIZER;
import static java.util.Objects.requireNonNull;
@@ -84,6 +85,7 @@
import android.net.VpnProfileState;
import android.net.VpnService;
import android.net.VpnTransportInfo;
+import android.net.ipsec.ike.ChildSaProposal;
import android.net.ipsec.ike.ChildSessionCallback;
import android.net.ipsec.ike.ChildSessionConfiguration;
import android.net.ipsec.ike.ChildSessionParams;
@@ -93,6 +95,7 @@
import android.net.ipsec.ike.IkeSessionConnectionInfo;
import android.net.ipsec.ike.IkeSessionParams;
import android.net.ipsec.ike.IkeTunnelConnectionParams;
+import android.net.ipsec.ike.exceptions.IkeIOException;
import android.net.ipsec.ike.exceptions.IkeNetworkLostException;
import android.net.ipsec.ike.exceptions.IkeNonProtocolException;
import android.net.ipsec.ike.exceptions.IkeProtocolException;
@@ -140,6 +143,7 @@
import com.android.server.DeviceIdleInternal;
import com.android.server.LocalServices;
import com.android.server.net.BaseNetworkObserver;
+import com.android.server.vcn.util.MtuUtils;
import com.android.server.vcn.util.PersistableBundleUtils;
import libcore.io.IoUtils;
@@ -152,6 +156,8 @@
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
+import java.net.NetworkInterface;
+import java.net.SocketException;
import java.net.UnknownHostException;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
@@ -165,6 +171,7 @@
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
+import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
@@ -551,6 +558,24 @@
return DATA_STALL_RESET_DELAYS_SEC[count];
}
}
+
+ /** Gets the MTU of an interface using Java NetworkInterface primitives */
+ public int getJavaNetworkInterfaceMtu(@Nullable String iface, int defaultValue)
+ throws SocketException {
+ if (iface == null) return defaultValue;
+
+ final NetworkInterface networkInterface = NetworkInterface.getByName(iface);
+ return networkInterface == null ? defaultValue : networkInterface.getMTU();
+ }
+
+ /** Calculates the VPN Network's max MTU based on underlying network and configuration */
+ public int calculateVpnMtu(
+ @NonNull List<ChildSaProposal> childProposals,
+ int maxMtu,
+ int underlyingMtu,
+ boolean isIpv4) {
+ return MtuUtils.getMtu(childProposals, maxMtu, underlyingMtu, isIpv4);
+ }
}
@VisibleForTesting
@@ -1397,6 +1422,11 @@
}
private LinkProperties makeLinkProperties() {
+ // The design of disabling IPv6 is only enabled for IKEv2 VPN because it needs additional
+ // logic to handle IPv6 only VPN, and the IPv6 only VPN may be restarted when its MTU
+ // is lower than 1280. The logic is controlled by IKEv2VpnRunner, so the design is only
+ // enabled for IKEv2 VPN.
+ final boolean disableIPV6 = (isIkev2VpnRunner() && mConfig.mtu < IPV6_MIN_MTU);
boolean allowIPv4 = mConfig.allowIPv4;
boolean allowIPv6 = mConfig.allowIPv6;
@@ -1406,6 +1436,7 @@
if (mConfig.addresses != null) {
for (LinkAddress address : mConfig.addresses) {
+ if (disableIPV6 && address.isIpv6()) continue;
lp.addLinkAddress(address);
allowIPv4 |= address.getAddress() instanceof Inet4Address;
allowIPv6 |= address.getAddress() instanceof Inet6Address;
@@ -1414,8 +1445,9 @@
if (mConfig.routes != null) {
for (RouteInfo route : mConfig.routes) {
+ final InetAddress address = route.getDestination().getAddress();
+ if (disableIPV6 && address instanceof Inet6Address) continue;
lp.addRoute(route);
- InetAddress address = route.getDestination().getAddress();
if (route.getType() == RouteInfo.RTN_UNICAST) {
allowIPv4 |= address instanceof Inet4Address;
@@ -1426,7 +1458,8 @@
if (mConfig.dnsServers != null) {
for (String dnsServer : mConfig.dnsServers) {
- InetAddress address = InetAddresses.parseNumericAddress(dnsServer);
+ final InetAddress address = InetAddresses.parseNumericAddress(dnsServer);
+ if (disableIPV6 && address instanceof Inet6Address) continue;
lp.addDnsServer(address);
allowIPv4 |= address instanceof Inet4Address;
allowIPv6 |= address instanceof Inet6Address;
@@ -1440,7 +1473,7 @@
NetworkStackConstants.IPV4_ADDR_ANY, 0), null /*gateway*/,
null /*iface*/, RTN_UNREACHABLE));
}
- if (!allowIPv6) {
+ if (!allowIPv6 || disableIPV6) {
lp.addRoute(new RouteInfo(new IpPrefix(
NetworkStackConstants.IPV6_ADDR_ANY, 0), null /*gateway*/,
null /*iface*/, RTN_UNREACHABLE));
@@ -1576,6 +1609,18 @@
updateState(DetailedState.DISCONNECTED, "agentDisconnect");
}
+ @GuardedBy("this")
+ private void startNewNetworkAgent(NetworkAgent oldNetworkAgent, String reason) {
+ // Initialize the state for a new agent, while keeping the old one connected
+ // in case this new connection fails.
+ mNetworkAgent = null;
+ updateState(DetailedState.CONNECTING, reason);
+ // Bringing up a new NetworkAgent to prevent the data leakage before tearing down the old
+ // NetworkAgent.
+ agentConnect();
+ agentDisconnect(oldNetworkAgent);
+ }
+
/**
* Establish a VPN network and return the file descriptor of the VPN interface. This methods
* returns {@code null} if the application is revoked or not prepared.
@@ -1665,16 +1710,7 @@
setUnderlyingNetworks(config.underlyingNetworks);
}
} else {
- // Initialize the state for a new agent, while keeping the old one connected
- // in case this new connection fails.
- mNetworkAgent = null;
- updateState(DetailedState.CONNECTING, "establish");
- // Set up forwarding and DNS rules.
- agentConnect();
- // Remove the old tun's user forwarding rules
- // The new tun's user rules have already been added above so they will take over
- // as rules are deleted. This prevents data leakage as the rules are moved over.
- agentDisconnect(oldNetworkAgent);
+ startNewNetworkAgent(oldNetworkAgent, "establish");
}
if (oldConnection != null) {
@@ -2711,6 +2747,17 @@
void onSessionLost(int token, @Nullable Exception exception);
}
+ private static boolean isIPv6Only(List<LinkAddress> linkAddresses) {
+ boolean hasIPV6 = false;
+ boolean hasIPV4 = false;
+ for (final LinkAddress address : linkAddresses) {
+ hasIPV6 |= address.isIpv6();
+ hasIPV4 |= address.isIpv4();
+ }
+
+ return hasIPV6 && !hasIPV4;
+ }
+
/**
* Internal class managing IKEv2/IPsec VPN connectivity
*
@@ -2924,15 +2971,27 @@
try {
final String interfaceName = mTunnelIface.getInterfaceName();
- final int maxMtu = mProfile.getMaxMtu();
final List<LinkAddress> internalAddresses = childConfig.getInternalAddresses();
final List<String> dnsAddrStrings = new ArrayList<>();
+ int vpnMtu;
+ vpnMtu = calculateVpnMtu();
+
+ // If the VPN is IPv6 only and its MTU is lower than 1280, mark the network as lost
+ // and send the VpnManager event to the VPN app.
+ if (isIPv6Only(internalAddresses) && vpnMtu < IPV6_MIN_MTU) {
+ onSessionLost(
+ token,
+ new IkeIOException(
+ new IOException("No valid addresses for MTU < 1280")));
+ return;
+ }
final Collection<RouteInfo> newRoutes = VpnIkev2Utils.getRoutesFromTrafficSelectors(
childConfig.getOutboundTrafficSelectors());
for (final LinkAddress address : internalAddresses) {
mTunnelIface.addAddress(address.getAddress(), address.getPrefixLength());
}
+
for (InetAddress addr : childConfig.getInternalDnsServers()) {
dnsAddrStrings.add(addr.getHostAddress());
}
@@ -2950,7 +3009,7 @@
if (mVpnRunner != this) return;
mInterface = interfaceName;
- mConfig.mtu = maxMtu;
+ mConfig.mtu = vpnMtu;
mConfig.interfaze = mInterface;
mConfig.addresses.clear();
@@ -3053,12 +3112,54 @@
// Ignore stale runner.
if (mVpnRunner != this) return;
+ final LinkProperties oldLp = makeLinkProperties();
+
+ final boolean underlyingNetworkHasChanged =
+ !Arrays.equals(mConfig.underlyingNetworks, new Network[]{network});
mConfig.underlyingNetworks = new Network[] {network};
- mNetworkCapabilities =
- new NetworkCapabilities.Builder(mNetworkCapabilities)
- .setUnderlyingNetworks(Collections.singletonList(network))
- .build();
- doSetUnderlyingNetworks(mNetworkAgent, Collections.singletonList(network));
+ mConfig.mtu = calculateVpnMtu();
+
+ final LinkProperties newLp = makeLinkProperties();
+
+ // If MTU is < 1280, IPv6 addresses will be removed. If there are no addresses
+ // left (e.g. IPv6-only VPN network), mark VPN as having lost the session.
+ if (newLp.getLinkAddresses().isEmpty()) {
+ onSessionLost(
+ token,
+ new IkeIOException(
+ new IOException("No valid addresses for MTU < 1280")));
+ return;
+ }
+
+ final Set<LinkAddress> removedAddrs = new HashSet<>(oldLp.getLinkAddresses());
+ removedAddrs.removeAll(newLp.getLinkAddresses());
+
+ // If addresses were removed despite no IKE config change, IPv6 addresses must
+ // have been removed due to MTU size. Restart the VPN to ensure all IPv6
+ // unconnected sockets on the new VPN network are closed and retried on the new
+ // VPN network.
+ if (!removedAddrs.isEmpty()) {
+ startNewNetworkAgent(
+ mNetworkAgent, "MTU too low for IPv6; restarting network agent");
+
+ for (LinkAddress removed : removedAddrs) {
+ mTunnelIface.removeAddress(
+ removed.getAddress(), removed.getPrefixLength());
+ }
+ } else {
+ // Put below 3 updates into else block is because agentConnect() will do
+ // those things, so there is no need to do the redundant work.
+ if (!newLp.equals(oldLp)) doSendLinkProperties(mNetworkAgent, newLp);
+ if (underlyingNetworkHasChanged) {
+ mNetworkCapabilities =
+ new NetworkCapabilities.Builder(mNetworkCapabilities)
+ .setUnderlyingNetworks(
+ Collections.singletonList(network))
+ .build();
+ doSetUnderlyingNetworks(mNetworkAgent,
+ Collections.singletonList(network));
+ }
+ }
}
mTunnelIface.setUnderlyingNetwork(network);
@@ -3108,6 +3209,60 @@
startOrMigrateIkeSession(network);
}
+ @NonNull
+ private IkeSessionParams getIkeSessionParams(@NonNull Network underlyingNetwork) {
+ final IkeTunnelConnectionParams ikeTunConnParams =
+ mProfile.getIkeTunnelConnectionParams();
+ if (ikeTunConnParams != null) {
+ final IkeSessionParams.Builder builder =
+ new IkeSessionParams.Builder(ikeTunConnParams.getIkeSessionParams())
+ .setNetwork(underlyingNetwork);
+ return builder.build();
+ } else {
+ return VpnIkev2Utils.buildIkeSessionParams(mContext, mProfile, underlyingNetwork);
+ }
+ }
+
+ @NonNull
+ private ChildSessionParams getChildSessionParams() {
+ final IkeTunnelConnectionParams ikeTunConnParams =
+ mProfile.getIkeTunnelConnectionParams();
+ if (ikeTunConnParams != null) {
+ return ikeTunConnParams.getTunnelModeChildSessionParams();
+ } else {
+ return VpnIkev2Utils.buildChildSessionParams(mProfile.getAllowedAlgorithms());
+ }
+ }
+
+ private int calculateVpnMtu() {
+ final Network underlyingNetwork = mIkeConnectionInfo.getNetwork();
+ final LinkProperties lp = mConnectivityManager.getLinkProperties(underlyingNetwork);
+ if (underlyingNetwork == null || lp == null) {
+ // Return the max MTU defined in VpnProfile as the fallback option when there is no
+ // underlying network or LinkProperties is null.
+ return mProfile.getMaxMtu();
+ }
+
+ int underlyingMtu = lp.getMtu();
+
+ // Try to get MTU from kernel if MTU is not set in LinkProperties.
+ if (underlyingMtu == 0) {
+ try {
+ underlyingMtu = mDeps.getJavaNetworkInterfaceMtu(lp.getInterfaceName(),
+ mProfile.getMaxMtu());
+ } catch (SocketException e) {
+ Log.d(TAG, "Got a SocketException when getting MTU from kernel: " + e);
+ return mProfile.getMaxMtu();
+ }
+ }
+
+ return mDeps.calculateVpnMtu(
+ getChildSessionParams().getSaProposals(),
+ mProfile.getMaxMtu(),
+ underlyingMtu,
+ mIkeConnectionInfo.getLocalAddress() instanceof Inet4Address);
+ }
+
/**
* Start a new IKE session.
*
@@ -3158,24 +3313,6 @@
// (non-default) network, and start the new one.
resetIkeState();
- // Get Ike options from IkeTunnelConnectionParams if it's available in the
- // profile.
- final IkeTunnelConnectionParams ikeTunConnParams =
- mProfile.getIkeTunnelConnectionParams();
- final IkeSessionParams ikeSessionParams;
- final ChildSessionParams childSessionParams;
- if (ikeTunConnParams != null) {
- final IkeSessionParams.Builder builder = new IkeSessionParams.Builder(
- ikeTunConnParams.getIkeSessionParams()).setNetwork(underlyingNetwork);
- ikeSessionParams = builder.build();
- childSessionParams = ikeTunConnParams.getTunnelModeChildSessionParams();
- } else {
- ikeSessionParams = VpnIkev2Utils.buildIkeSessionParams(
- mContext, mProfile, underlyingNetwork);
- childSessionParams = VpnIkev2Utils.buildChildSessionParams(
- mProfile.getAllowedAlgorithms());
- }
-
// TODO: Remove the need for adding two unused addresses with
// IPsec tunnels.
final InetAddress address = InetAddress.getLocalHost();
@@ -3193,8 +3330,8 @@
mSession =
mIkev2SessionCreator.createIkeSession(
mContext,
- ikeSessionParams,
- childSessionParams,
+ getIkeSessionParams(underlyingNetwork),
+ getChildSessionParams(),
mExecutor,
new VpnIkev2Utils.IkeSessionCallbackImpl(
TAG, IkeV2VpnRunner.this, token),
diff --git a/services/core/java/com/android/server/display/DisplayDeviceConfig.java b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
index a3b1a42..523a2dc 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceConfig.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
@@ -699,7 +699,6 @@
*/
public float getNitsFromBacklight(float backlight) {
if (mBacklightToNitsSpline == null) {
- Slog.wtf(TAG, "requesting nits when no mapping exists.");
return NITS_INVALID;
}
backlight = Math.max(backlight, mBacklightMinimum);
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 9cb8f43..1225d99 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -144,6 +144,7 @@
import android.window.ImeOnBackInvokedDispatcher;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.content.PackageMonitor;
import com.android.internal.infra.AndroidFuture;
import com.android.internal.inputmethod.DirectBootAwareness;
@@ -1592,8 +1593,13 @@
private final InputMethodManagerService mService;
public Lifecycle(Context context) {
+ this(context, new InputMethodManagerService(context));
+ }
+
+ public Lifecycle(
+ Context context, @NonNull InputMethodManagerService inputMethodManagerService) {
super(context);
- mService = new InputMethodManagerService(context);
+ mService = inputMethodManagerService;
}
@Override
@@ -1668,12 +1674,25 @@
}
public InputMethodManagerService(Context context) {
+ this(context, null, null);
+ }
+
+ @VisibleForTesting
+ InputMethodManagerService(
+ Context context,
+ @Nullable ServiceThread serviceThreadForTesting,
+ @Nullable InputMethodBindingController bindingControllerForTesting) {
mContext = context;
mRes = context.getResources();
// TODO(b/196206770): Disallow I/O on this thread. Currently it's needed for loading
// additional subtypes in switchUserOnHandlerLocked().
- final ServiceThread thread = new ServiceThread(
- HANDLER_THREAD_NAME, Process.THREAD_PRIORITY_FOREGROUND, true /* allowIo */);
+ final ServiceThread thread =
+ serviceThreadForTesting != null
+ ? serviceThreadForTesting
+ : new ServiceThread(
+ HANDLER_THREAD_NAME,
+ Process.THREAD_PRIORITY_FOREGROUND,
+ true /* allowIo */);
thread.start();
mHandler = Handler.createAsync(thread.getLooper(), this);
// Note: SettingsObserver doesn't register observers in its constructor.
@@ -1701,10 +1720,13 @@
updateCurrentProfileIds();
AdditionalSubtypeUtils.load(mAdditionalSubtypeMap, userId);
- mSwitchingController = InputMethodSubtypeSwitchingController.createInstanceLocked(
- mSettings, context);
+ mSwitchingController =
+ InputMethodSubtypeSwitchingController.createInstanceLocked(mSettings, context);
mMenuController = new InputMethodMenuController(this);
- mBindingController = new InputMethodBindingController(this);
+ mBindingController =
+ bindingControllerForTesting != null
+ ? bindingControllerForTesting
+ : new InputMethodBindingController(this);
mAutofillController = new AutofillSuggestionsController(this);
mPreventImeStartupUnlessTextEditor = mRes.getBoolean(
com.android.internal.R.bool.config_preventImeStartupUnlessTextEditor);
@@ -3673,6 +3695,7 @@
// UI for input.
if (isTextEditor && editorInfo != null
&& shouldRestoreImeVisibility(windowToken, softInputMode)) {
+ if (DEBUG) Slog.v(TAG, "Will show input to restore visibility");
res = startInputUncheckedLocked(cs, inputContext, remoteAccessibilityInputConnection,
editorInfo, startInputFlags, startInputReason, unverifiedTargetSdkVersion,
imeDispatcher);
@@ -3719,11 +3742,17 @@
imeDispatcher);
didStart = true;
}
- showCurrentInputLocked(windowToken, InputMethodManager.SHOW_IMPLICIT, null,
+ showCurrentInputLocked(
+ windowToken,
+ InputMethodManager.SHOW_IMPLICIT,
+ null,
SoftInputShowHideReason.SHOW_AUTO_EDITOR_FORWARD_NAV);
}
break;
case LayoutParams.SOFT_INPUT_STATE_UNCHANGED:
+ if (DEBUG) {
+ Slog.v(TAG, "Window asks to keep the input in whatever state it was last in");
+ }
// Do nothing.
break;
case LayoutParams.SOFT_INPUT_STATE_HIDDEN:
@@ -3794,6 +3823,7 @@
// To maintain compatibility, we are now hiding the IME when we don't have
// an editor upon refocusing a window.
if (startInputByWinGainedFocus) {
+ if (DEBUG) Slog.v(TAG, "Same window without editor will hide input");
hideCurrentInputLocked(mCurFocusedWindow, 0, null,
SoftInputShowHideReason.HIDE_SAME_WINDOW_FOCUSED_WITHOUT_EDITOR);
}
@@ -3807,6 +3837,7 @@
// 1) SOFT_INPUT_STATE_UNCHANGED state without an editor
// 2) SOFT_INPUT_STATE_VISIBLE state without an editor
// 3) SOFT_INPUT_STATE_ALWAYS_VISIBLE state without an editor
+ if (DEBUG) Slog.v(TAG, "Window without editor will hide input");
hideCurrentInputLocked(mCurFocusedWindow, 0, null,
SoftInputShowHideReason.HIDE_WINDOW_GAINED_FOCUS_WITHOUT_EDITOR);
}
@@ -4382,7 +4413,7 @@
* a stylus deviceId is not already registered on device.
*/
@BinderThread
- @EnforcePermission(Manifest.permission.INJECT_EVENTS)
+ @EnforcePermission(Manifest.permission.TEST_INPUT_METHOD)
@Override
public void addVirtualStylusIdForTestSession(IInputMethodClient client) {
int uid = Binder.getCallingUid();
diff --git a/services/core/java/com/android/server/location/contexthub/ContextHubService.java b/services/core/java/com/android/server/location/contexthub/ContextHubService.java
index 51851be..6232028 100644
--- a/services/core/java/com/android/server/location/contexthub/ContextHubService.java
+++ b/services/core/java/com/android/server/location/contexthub/ContextHubService.java
@@ -129,7 +129,7 @@
new RemoteCallbackList<>();
// Proxy object to communicate with the Context Hub HAL
- private IContextHubWrapper mContextHubWrapper;
+ private final IContextHubWrapper mContextHubWrapper;
// The manager for transaction queue
private ContextHubTransactionManager mTransactionManager;
@@ -210,8 +210,24 @@
}
public ContextHubService(Context context, IContextHubWrapper contextHubWrapper) {
+ Log.i(TAG, "Starting Context Hub Service init");
mContext = context;
- init(contextHubWrapper, /* isFirstInit= */ true);
+ long startTimeNs = SystemClock.elapsedRealtimeNanos();
+ mContextHubWrapper = contextHubWrapper;
+ if (!initContextHubServiceState(startTimeNs)) {
+ Log.e(TAG, "Failed to initialize the Context Hub Service");
+ return;
+ }
+ initDefaultClientMap();
+
+ initLocationSettingNotifications();
+ initWifiSettingNotifications();
+ initAirplaneModeSettingNotifications();
+ initMicrophoneSettingNotifications();
+ initBtSettingNotifications();
+
+ scheduleDailyMetricSnapshot();
+ Log.i(TAG, "Finished Context Hub Service init");
}
/**
@@ -293,11 +309,10 @@
* Initializes the private state of the ContextHubService
*
* @param startTimeNs the start time when init was called
- * @param isFirstInit if true, this is the first time init is called - boot time
*
* @return if mContextHubWrapper is not null and a full state init was done
*/
- private boolean initContextHubServiceState(long startTimeNs, boolean isFirstInit) {
+ private boolean initContextHubServiceState(long startTimeNs) {
if (mContextHubWrapper == null) {
mTransactionManager = null;
mClientManager = null;
@@ -317,12 +332,10 @@
hubInfo = new Pair(Collections.emptyList(), Collections.emptyList());
}
- if (isFirstInit) {
- long bootTimeNs = SystemClock.elapsedRealtimeNanos() - startTimeNs;
- int numContextHubs = hubInfo.first.size();
- ContextHubStatsLog.write(ContextHubStatsLog.CONTEXT_HUB_BOOTED, bootTimeNs,
- numContextHubs);
- }
+ long bootTimeNs = SystemClock.elapsedRealtimeNanos() - startTimeNs;
+ int numContextHubs = hubInfo.first.size();
+ ContextHubStatsLog.write(ContextHubStatsLog.CONTEXT_HUB_BOOTED, bootTimeNs,
+ numContextHubs);
mContextHubIdToInfoMap = Collections.unmodifiableMap(
ContextHubServiceUtil.createContextHubInfoMap(hubInfo.first));
@@ -749,31 +762,6 @@
}
/**
- * Handles a service restart or service init for the first time
- *
- * @param contextHubWrapper the Context Hub wrapper
- * @param isFirstInit if true, this is the first time init is called - boot time
- */
- private void init(IContextHubWrapper contextHubWrapper, boolean isFirstInit) {
- Log.i(TAG, "Starting Context Hub Service init");
- long startTimeNs = SystemClock.elapsedRealtimeNanos();
- mContextHubWrapper = contextHubWrapper;
- if (!initContextHubServiceState(startTimeNs, isFirstInit)) {
- Log.e(TAG, "Failed to initialize the Context Hub Service");
- return;
- }
- initDefaultClientMap();
-
- initLocationSettingNotifications();
- initWifiSettingNotifications();
- initAirplaneModeSettingNotifications();
- initMicrophoneSettingNotifications();
- initBtSettingNotifications();
-
- scheduleDailyMetricSnapshot();
- }
-
- /**
* Handles a unicast or broadcast message from a nanoapp.
*
* @param contextHubId the ID of the hub the message came from
diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
index 439e9bd..c67d54f 100644
--- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
+++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
@@ -151,7 +151,7 @@
mContext.registerReceiver(mScreenOnOffReceiver, screenOnOffIntentFilter);
}
- // Methods that implement MediaRouter2 operations.
+ // Start of methods that implement MediaRouter2 operations.
@NonNull
public void enforceMediaContentControlPermission() {
@@ -199,46 +199,6 @@
}
}
- @NonNull
- public RoutingSessionInfo getSystemSessionInfo(
- @Nullable String packageName, boolean setDeviceRouteSelected) {
- final int uid = Binder.getCallingUid();
- final int userId = UserHandle.getUserHandleForUid(uid).getIdentifier();
- final boolean hasModifyAudioRoutingPermission = mContext.checkCallingOrSelfPermission(
- android.Manifest.permission.MODIFY_AUDIO_ROUTING)
- == PackageManager.PERMISSION_GRANTED;
-
- final long token = Binder.clearCallingIdentity();
- try {
- RoutingSessionInfo systemSessionInfo = null;
- synchronized (mLock) {
- UserRecord userRecord = getOrCreateUserRecordLocked(userId);
- List<RoutingSessionInfo> sessionInfos;
- if (hasModifyAudioRoutingPermission) {
- if (setDeviceRouteSelected) {
- systemSessionInfo = userRecord.mHandler.mSystemProvider
- .generateDeviceRouteSelectedSessionInfo(packageName);
- } else {
- sessionInfos = userRecord.mHandler.mSystemProvider.getSessionInfos();
- if (sessionInfos != null && !sessionInfos.isEmpty()) {
- systemSessionInfo = new RoutingSessionInfo.Builder(sessionInfos.get(0))
- .setClientPackageName(packageName).build();
- } else {
- Slog.w(TAG, "System provider does not have any session info.");
- }
- }
- } else {
- systemSessionInfo = new RoutingSessionInfo.Builder(
- userRecord.mHandler.mSystemProvider.getDefaultSessionInfo())
- .setClientPackageName(packageName).build();
- }
- }
- return systemSessionInfo;
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
-
public void registerRouter2(@NonNull IMediaRouter2 router, @NonNull String packageName) {
Objects.requireNonNull(router, "router must not be null");
if (TextUtils.isEmpty(packageName)) {
@@ -418,7 +378,9 @@
}
}
- // Methods that implement MediaRouter2Manager operations.
+ // End of methods that implement MediaRouter2 operations.
+
+ // Start of methods that implement MediaRouter2Manager operations.
@NonNull
public List<RoutingSessionInfo> getRemoteSessions(@NonNull IMediaRouter2Manager manager) {
@@ -610,6 +572,52 @@
}
}
+ // End of methods that implement MediaRouter2Manager operations.
+
+ // Start of methods that implements operations for both MediaRouter2 and MediaRouter2Manager.
+
+ @NonNull
+ public RoutingSessionInfo getSystemSessionInfo(
+ @Nullable String packageName, boolean setDeviceRouteSelected) {
+ final int uid = Binder.getCallingUid();
+ final int userId = UserHandle.getUserHandleForUid(uid).getIdentifier();
+ final boolean hasModifyAudioRoutingPermission = mContext.checkCallingOrSelfPermission(
+ android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ == PackageManager.PERMISSION_GRANTED;
+
+ final long token = Binder.clearCallingIdentity();
+ try {
+ RoutingSessionInfo systemSessionInfo = null;
+ synchronized (mLock) {
+ UserRecord userRecord = getOrCreateUserRecordLocked(userId);
+ List<RoutingSessionInfo> sessionInfos;
+ if (hasModifyAudioRoutingPermission) {
+ if (setDeviceRouteSelected) {
+ systemSessionInfo = userRecord.mHandler.mSystemProvider
+ .generateDeviceRouteSelectedSessionInfo(packageName);
+ } else {
+ sessionInfos = userRecord.mHandler.mSystemProvider.getSessionInfos();
+ if (sessionInfos != null && !sessionInfos.isEmpty()) {
+ systemSessionInfo = new RoutingSessionInfo.Builder(sessionInfos.get(0))
+ .setClientPackageName(packageName).build();
+ } else {
+ Slog.w(TAG, "System provider does not have any session info.");
+ }
+ }
+ } else {
+ systemSessionInfo = new RoutingSessionInfo.Builder(
+ userRecord.mHandler.mSystemProvider.getDefaultSessionInfo())
+ .setClientPackageName(packageName).build();
+ }
+ }
+ return systemSessionInfo;
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ // End of methods that implements operations for both MediaRouter2 and MediaRouter2Manager.
+
public void dump(@NonNull PrintWriter pw, @NonNull String prefix) {
pw.println(prefix + "MediaRouter2ServiceImpl");
@@ -678,6 +686,8 @@
return mUserManagerInternal.getProfileParentId(userId) == mCurrentActiveUserId;
}
+ // Start of locked methods that are used by MediaRouter2.
+
@GuardedBy("mLock")
private void registerRouter2Locked(@NonNull IMediaRouter2 router, int uid, int pid,
@NonNull String packageName, int userId, boolean hasConfigureWifiDisplayPermission,
@@ -952,6 +962,10 @@
DUMMY_REQUEST_ID, routerRecord, uniqueSessionId));
}
+ // End of locked methods that are used by MediaRouter2.
+
+ // Start of locked methods that are used by MediaRouter2Manager.
+
private List<RoutingSessionInfo> getRemoteSessionsLocked(
@NonNull IMediaRouter2Manager manager) {
final IBinder binder = manager.asBinder();
@@ -1260,6 +1274,10 @@
uniqueRequestId, routerRecord, uniqueSessionId));
}
+ // End of locked methods that are used by MediaRouter2Manager.
+
+ // Start of locked methods that are used by both MediaRouter2 and MediaRouter2Manager.
+
@GuardedBy("mLock")
private UserRecord getOrCreateUserRecordLocked(int userId) {
UserRecord userRecord = mUserRecords.get(userId);
@@ -1294,6 +1312,8 @@
}
}
+ // End of locked methods that are used by both MediaRouter2 and MediaRouter2Manager.
+
static long toUniqueRequestId(int requesterId, int originalRequestId) {
return ((long) requesterId << 32) | originalRequestId;
}
diff --git a/services/core/java/com/android/server/pm/ApexPackageInfo.java b/services/core/java/com/android/server/pm/ApexPackageInfo.java
deleted file mode 100644
index 672ae2e..0000000
--- a/services/core/java/com/android/server/pm/ApexPackageInfo.java
+++ /dev/null
@@ -1,419 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.pm;
-
-import static com.android.server.pm.ApexManager.MATCH_ACTIVE_PACKAGE;
-import static com.android.server.pm.ApexManager.MATCH_FACTORY_PACKAGE;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.apex.ApexInfo;
-import android.content.pm.PackageManager;
-import android.util.ArrayMap;
-import android.util.Pair;
-import android.util.PrintWriterPrinter;
-
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.util.IndentingPrintWriter;
-import com.android.internal.util.Preconditions;
-import com.android.server.pm.parsing.PackageParser2;
-import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
-import com.android.server.pm.parsing.pkg.ParsedPackage;
-import com.android.server.pm.pkg.AndroidPackage;
-import com.android.server.pm.pkg.PackageStateInternal;
-import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
-
-import java.io.File;
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.concurrent.ExecutorService;
-
-/**
- * A temporary holder to store PackageInfo for scanned apex packages. We will unify the scan/install
- * flows of APK and APEX and PMS will be the only source of truth for all package information
- * including both APK and APEX. This class will no longer be needed when the migration is done.
- */
-class ApexPackageInfo {
- public static final boolean ENABLE_FEATURE_SCAN_APEX = true;
-
- private static final String TAG = "ApexManager";
- private static final String VNDK_APEX_MODULE_NAME_PREFIX = "com.android.vndk.";
-
- private final Object mLock = new Object();
-
- @GuardedBy("mLock")
- private List<Pair<ApexInfo, AndroidPackage>> mAllPackagesCache;
-
- @Nullable
- private final PackageManagerService mPackageManager;
-
- ApexPackageInfo() {
- mPackageManager = null;
- }
-
- ApexPackageInfo(@NonNull PackageManagerService pms) {
- mPackageManager = pms;
- }
-
- /**
- * Called by package manager service to scan apex package files when device boots up.
- *
- * @param allPackages All apex packages to scan.
- * @param packageParser The package parser to support apex package parsing and caching parsed
- * results.
- * @param executorService An executor to support parallel package parsing.
- */
- List<ApexManager.ScanResult> scanApexPackages(ApexInfo[] allPackages,
- @NonNull PackageParser2 packageParser, @NonNull ExecutorService executorService) {
- synchronized (mLock) {
- return scanApexPackagesInternalLocked(allPackages, packageParser, executorService);
- }
- }
-
- void notifyScanResult(List<ApexManager.ScanResult> scanResults) {
- synchronized (mLock) {
- notifyScanResultLocked(scanResults);
- }
- }
-
- /**
- * Retrieves information about an APEX package.
- *
- * @param packageName the package name to look for. Note that this is the package name reported
- * in the APK container manifest (i.e. AndroidManifest.xml), which might
- * differ from the one reported in the APEX manifest (i.e.
- * apex_manifest.json).
- * @param flags the type of package to return. This may match to active packages
- * and factory (pre-installed) packages.
- * @return a PackageInfo object with the information about the package, or null if the package
- * is not found.
- */
- @Nullable
- Pair<ApexInfo, AndroidPackage> getPackageInfo(String packageName,
- @ApexManager.PackageInfoFlags int flags) {
- synchronized (mLock) {
- Preconditions.checkState(mAllPackagesCache != null,
- "APEX packages have not been scanned");
- boolean matchActive = (flags & MATCH_ACTIVE_PACKAGE) != 0;
- boolean matchFactory = (flags & MATCH_FACTORY_PACKAGE) != 0;
- for (int i = 0, size = mAllPackagesCache.size(); i < size; i++) {
- final Pair<ApexInfo, AndroidPackage> pair = mAllPackagesCache.get(i);
- var apexInfo = pair.first;
- var pkg = pair.second;
- if (!pkg.getPackageName().equals(packageName)) {
- continue;
- }
- if ((matchActive && apexInfo.isActive)
- || (matchFactory && apexInfo.isFactory)) {
- return pair;
- }
- }
- return null;
- }
- }
-
- /**
- * Retrieves information about all active APEX packages.
- *
- * @return list containing information about different active packages.
- */
- @NonNull
- List<Pair<ApexInfo, AndroidPackage>> getActivePackages() {
- synchronized (mLock) {
- Preconditions.checkState(mAllPackagesCache != null,
- "APEX packages have not been scanned");
- final List<Pair<ApexInfo, AndroidPackage>> activePackages = new ArrayList<>();
- for (int i = 0; i < mAllPackagesCache.size(); i++) {
- final var pair = mAllPackagesCache.get(i);
- if (pair.first.isActive) {
- activePackages.add(pair);
- }
- }
- return activePackages;
- }
- }
-
- /**
- * Retrieves information about all pre-installed APEX packages.
- *
- * @return list containing information about different pre-installed packages.
- */
- @NonNull
- List<Pair<ApexInfo, AndroidPackage>> getFactoryPackages() {
- synchronized (mLock) {
- Preconditions.checkState(mAllPackagesCache != null,
- "APEX packages have not been scanned");
- final List<Pair<ApexInfo, AndroidPackage>> factoryPackages = new ArrayList<>();
- for (int i = 0; i < mAllPackagesCache.size(); i++) {
- final var pair = mAllPackagesCache.get(i);
- if (pair.first.isFactory) {
- factoryPackages.add(pair);
- }
- }
- return factoryPackages;
- }
- }
-
- /**
- * Retrieves information about all inactive APEX packages.
- *
- * @return list containing information about different inactive packages.
- */
- @NonNull
- List<Pair<ApexInfo, AndroidPackage>> getInactivePackages() {
- synchronized (mLock) {
- Preconditions.checkState(mAllPackagesCache != null,
- "APEX packages have not been scanned");
- final List<Pair<ApexInfo, AndroidPackage>> inactivePackages = new ArrayList<>();
- for (int i = 0; i < mAllPackagesCache.size(); i++) {
- final var pair = mAllPackagesCache.get(i);
- if (!pair.first.isActive) {
- inactivePackages.add(pair);
- }
- }
- return inactivePackages;
- }
- }
-
- /**
- * Checks if {@code packageName} is an apex package.
- *
- * @param packageName package to check.
- * @return {@code true} if {@code packageName} is an apex package.
- */
- boolean isApexPackage(String packageName) {
- synchronized (mLock) {
- Preconditions.checkState(mAllPackagesCache != null,
- "APEX packages have not been scanned");
- for (int i = 0, size = mAllPackagesCache.size(); i < size; i++) {
- final var pair = mAllPackagesCache.get(i);
- if (pair.second.getPackageName().equals(packageName)) {
- return true;
- }
- }
- }
- return false;
- }
-
- /**
- * Called to update cached PackageInfo when installing rebootless APEX.
- */
- void notifyPackageInstalled(ApexInfo apexInfo, PackageParser2 packageParser)
- throws PackageManagerException {
- final int flags = PackageManager.GET_META_DATA
- | PackageManager.GET_SIGNING_CERTIFICATES
- | PackageManager.GET_SIGNATURES;
- final ParsedPackage parsedPackage = packageParser.parsePackage(
- new File(apexInfo.modulePath), flags, /* useCaches= */ false);
- notifyPackageInstalled(apexInfo, parsedPackage.hideAsFinal());
- }
-
- void notifyPackageInstalled(ApexInfo apexInfo, AndroidPackage pkg) {
- final String packageName = pkg.getPackageName();
- synchronized (mLock) {
- for (int i = 0, size = mAllPackagesCache.size(); i < size; i++) {
- var pair = mAllPackagesCache.get(i);
- var oldApexInfo = pair.first;
- var oldApexPkg = pair.second;
- if (oldApexInfo.isActive && oldApexPkg.getPackageName().equals(packageName)) {
- if (oldApexInfo.isFactory) {
- oldApexInfo.isActive = false;
- mAllPackagesCache.add(Pair.create(apexInfo, pkg));
- } else {
- mAllPackagesCache.set(i, Pair.create(apexInfo, pkg));
- }
- break;
- }
- }
- }
- }
-
- /**
- * Dumps various state information to the provided {@link PrintWriter} object.
- *
- * @param pw the {@link PrintWriter} object to send information to.
- * @param packageName a {@link String} containing a package name, or {@code null}. If set, only
- * information about that specific package will be dumped.
- */
- void dump(PrintWriter pw, @Nullable String packageName) {
- final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ", 120);
- synchronized (mLock) {
- if (mAllPackagesCache == null) {
- ipw.println("APEX packages have not been scanned");
- return;
- }
- }
- ipw.println("Active APEX packages:");
- dumpPackages(getActivePackages(), packageName, ipw);
- ipw.println("Inactive APEX packages:");
- dumpPackages(getInactivePackages(), packageName, ipw);
- ipw.println("Factory APEX packages:");
- dumpPackages(getFactoryPackages(), packageName, ipw);
- }
-
- @GuardedBy("mLock")
- private void notifyScanResultLocked(List<ApexManager.ScanResult> scanResults) {
- mAllPackagesCache = new ArrayList<>();
- final int flags = PackageManager.GET_META_DATA
- | PackageManager.GET_SIGNING_CERTIFICATES
- | PackageManager.GET_SIGNATURES;
-
- HashSet<String> activePackagesSet = new HashSet<>();
- HashSet<String> factoryPackagesSet = new HashSet<>();
- for (ApexManager.ScanResult result : scanResults) {
- ApexInfo ai = result.apexInfo;
- String packageName = result.pkg.getPackageName();
- if (!packageName.equals(result.packageName)) {
- throw new IllegalStateException("Unmatched package name: "
- + result.packageName + " != " + packageName
- + ", path=" + ai.modulePath);
- }
- mAllPackagesCache.add(Pair.create(ai, result.pkg));
- if (ai.isActive) {
- if (!activePackagesSet.add(packageName)) {
- throw new IllegalStateException(
- "Two active packages have the same name: " + packageName);
- }
- }
- if (ai.isFactory) {
- // Don't throw when the duplicating APEX is VNDK APEX
- if (!factoryPackagesSet.add(packageName)
- && !ai.moduleName.startsWith(VNDK_APEX_MODULE_NAME_PREFIX)) {
- throw new IllegalStateException(
- "Two factory packages have the same name: " + packageName);
- }
- }
- }
- }
-
- @GuardedBy("mLock")
- private List<ApexManager.ScanResult> scanApexPackagesInternalLocked(final ApexInfo[] allPkgs,
- PackageParser2 packageParser, ExecutorService executorService) {
- if (allPkgs == null || allPkgs.length == 0) {
- notifyScanResultLocked(Collections.EMPTY_LIST);
- return Collections.EMPTY_LIST;
- }
-
- ArrayMap<File, ApexInfo> parsingApexInfo = new ArrayMap<>();
- ParallelPackageParser parallelPackageParser =
- new ParallelPackageParser(packageParser, executorService);
- for (ApexInfo ai : allPkgs) {
- File apexFile = new File(ai.modulePath);
- parallelPackageParser.submit(apexFile,
- ParsingPackageUtils.PARSE_COLLECT_CERTIFICATES);
- parsingApexInfo.put(apexFile, ai);
- }
-
- List<ApexManager.ScanResult> results = new ArrayList<>(parsingApexInfo.size());
- // Process results one by one
- for (int i = 0; i < parsingApexInfo.size(); i++) {
- ParallelPackageParser.ParseResult parseResult = parallelPackageParser.take();
- Throwable throwable = parseResult.throwable;
- ApexInfo ai = parsingApexInfo.get(parseResult.scanFile);
-
- if (throwable == null) {
- // TODO: When ENABLE_FEATURE_SCAN_APEX is finalized, remove this and the entire
- // calling path code
- ScanPackageUtils.applyPolicy(parseResult.parsedPackage,
- PackageManagerService.SCAN_AS_SYSTEM,
- mPackageManager == null ? null : mPackageManager.getPlatformPackage(),
- false);
- // Calling hideAsFinal to assign derived fields for the app info flags.
- AndroidPackage finalPkg = parseResult.parsedPackage.hideAsFinal();
- results.add(new ApexManager.ScanResult(ai, finalPkg, finalPkg.getPackageName()));
- } else if (throwable instanceof PackageManagerException) {
- throw new IllegalStateException("Unable to parse: " + ai.modulePath, throwable);
- } else {
- throw new IllegalStateException("Unexpected exception occurred while parsing "
- + ai.modulePath, throwable);
- }
- }
-
- notifyScanResultLocked(results);
- return results;
- }
-
- /**
- * @see #dumpPackages(List, String, IndentingPrintWriter)
- */
- static void dumpPackageStates(List<PackageStateInternal> packageStates, boolean isActive,
- @Nullable String packageName, IndentingPrintWriter ipw) {
- ipw.println();
- ipw.increaseIndent();
- for (int i = 0, size = packageStates.size(); i < size; i++) {
- final var packageState = packageStates.get(i);
- var pkg = packageState.getPkg();
- if (packageName != null && !packageName.equals(pkg.getPackageName())) {
- continue;
- }
- ipw.println(pkg.getPackageName());
- ipw.increaseIndent();
- ipw.println("Version: " + pkg.getLongVersionCode());
- ipw.println("Path: " + pkg.getBaseApkPath());
- ipw.println("IsActive: " + isActive);
- ipw.println("IsFactory: " + !packageState.isUpdatedSystemApp());
- ipw.println("ApplicationInfo: ");
- ipw.increaseIndent();
- // TODO: Dump the package manually
- AndroidPackageUtils.generateAppInfoWithoutState(pkg)
- .dump(new PrintWriterPrinter(ipw), "");
- ipw.decreaseIndent();
- ipw.decreaseIndent();
- }
- ipw.decreaseIndent();
- ipw.println();
- }
-
- /**
- * Dump information about the packages contained in a particular cache
- * @param packagesCache the cache to print information about.
- * @param packageName a {@link String} containing a package name, or {@code null}. If set,
- * only information about that specific package will be dumped.
- * @param ipw the {@link IndentingPrintWriter} object to send information to.
- */
- static void dumpPackages(List<Pair<ApexInfo, AndroidPackage>> packagesCache,
- @Nullable String packageName, IndentingPrintWriter ipw) {
- ipw.println();
- ipw.increaseIndent();
- for (int i = 0, size = packagesCache.size(); i < size; i++) {
- final var pair = packagesCache.get(i);
- var apexInfo = pair.first;
- var pkg = pair.second;
- if (packageName != null && !packageName.equals(pkg.getPackageName())) {
- continue;
- }
- ipw.println(pkg.getPackageName());
- ipw.increaseIndent();
- ipw.println("Version: " + pkg.getLongVersionCode());
- ipw.println("Path: " + pkg.getBaseApkPath());
- ipw.println("IsActive: " + apexInfo.isActive);
- ipw.println("IsFactory: " + apexInfo.isFactory);
- ipw.println("ApplicationInfo: ");
- ipw.increaseIndent();
- // TODO: Dump the package manually
- AndroidPackageUtils.generateAppInfoWithoutState(pkg)
- .dump(new PrintWriterPrinter(ipw), "");
- ipw.decreaseIndent();
- ipw.decreaseIndent();
- }
- ipw.decreaseIndent();
- ipw.println();
- }
-}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/pm/AppDataHelper.java b/services/core/java/com/android/server/pm/AppDataHelper.java
index b8e1e9a..f3cfa95 100644
--- a/services/core/java/com/android/server/pm/AppDataHelper.java
+++ b/services/core/java/com/android/server/pm/AppDataHelper.java
@@ -61,7 +61,7 @@
/**
* Prepares app data for users
*/
-final class AppDataHelper {
+public class AppDataHelper {
private static final boolean DEBUG_APP_DATA = false;
private final PackageManagerService mPm;
diff --git a/services/core/java/com/android/server/pm/AppsFilterImpl.java b/services/core/java/com/android/server/pm/AppsFilterImpl.java
index e3a2fb2..2e67bf2 100644
--- a/services/core/java/com/android/server/pm/AppsFilterImpl.java
+++ b/services/core/java/com/android/server/pm/AppsFilterImpl.java
@@ -492,9 +492,11 @@
*
* @param newPkgSetting the new setting being added
* @param isReplace if the package is being replaced and may need extra cleanup.
+ * @param retainImplicitGrantOnReplace {@code true} to retain implicit grant access if
+ * the package is being replaced.
*/
public void addPackage(Computer snapshot, PackageStateInternal newPkgSetting,
- boolean isReplace) {
+ boolean isReplace, boolean retainImplicitGrantOnReplace) {
final long currentTimeUs = SystemClock.currentTimeMicro();
final int logType = isReplace
? PACKAGE_MANAGER_APPS_FILTER_CACHE_UPDATE_REPORTED__EVENT_TYPE__PACKAGE_REPLACED
@@ -505,7 +507,8 @@
try {
if (isReplace) {
// let's first remove any prior rules for this package
- removePackageInternal(snapshot, newPkgSetting, true /*isReplace*/);
+ removePackageInternal(snapshot, newPkgSetting,
+ true /*isReplace*/, retainImplicitGrantOnReplace);
}
final ArrayMap<String, ? extends PackageStateInternal> settings =
snapshot.getPackageStates();
@@ -1016,13 +1019,14 @@
}
/**
- * Equivalent to calling {@link #addPackage(Computer, PackageStateInternal, boolean)}
- * with {@code isReplace} equal to {@code false}.
+ * Equivalent to calling {@link #addPackage(Computer, PackageStateInternal, boolean, boolean)}
+ * with {@code isReplace} and {@code retainImplicitGrantOnReplace} equal to {@code false}.
*
- * @see AppsFilterImpl#addPackage(Computer, PackageStateInternal, boolean)
+ * @see AppsFilterImpl#addPackage(Computer, PackageStateInternal, boolean, boolean)
*/
public void addPackage(Computer snapshot, PackageStateInternal newPkgSetting) {
- addPackage(snapshot, newPkgSetting, false /* isReplace */);
+ addPackage(snapshot, newPkgSetting, false /* isReplace */,
+ false /* retainImplicitGrantOnReplace */);
}
/**
@@ -1032,7 +1036,8 @@
*/
public void removePackage(Computer snapshot, PackageStateInternal setting) {
final long currentTimeUs = SystemClock.currentTimeMicro();
- removePackageInternal(snapshot, setting, false /* isReplace */);
+ removePackageInternal(snapshot, setting,
+ false /* isReplace */, false /* retainImplicitGrantOnReplace */);
logCacheUpdated(
PACKAGE_MANAGER_APPS_FILTER_CACHE_UPDATE_REPORTED__EVENT_TYPE__PACKAGE_DELETED,
SystemClock.currentTimeMicro() - currentTimeUs,
@@ -1046,33 +1051,37 @@
*
* @param setting the setting of the package being removed.
* @param isReplace if the package is being replaced.
+ * @param retainImplicitGrantOnReplace {@code true} to retain implicit grant access if
+ * the package is being replaced.
*/
private void removePackageInternal(Computer snapshot, PackageStateInternal setting,
- boolean isReplace) {
+ boolean isReplace, boolean retainImplicitGrantOnReplace) {
final ArraySet<String> additionalChangedPackages;
final ArrayMap<String, ? extends PackageStateInternal> settings =
snapshot.getPackageStates();
final UserInfo[] users = snapshot.getUserInfos();
final Collection<SharedUserSetting> sharedUserSettings = snapshot.getAllSharedUsers();
final int userCount = users.length;
- synchronized (mImplicitlyQueryableLock) {
- for (int u = 0; u < userCount; u++) {
- final int userId = users[u].id;
- final int removingUid = UserHandle.getUid(userId, setting.getAppId());
- mImplicitlyQueryable.remove(removingUid);
- for (int i = mImplicitlyQueryable.size() - 1; i >= 0; i--) {
- mImplicitlyQueryable.remove(mImplicitlyQueryable.keyAt(i),
- removingUid);
- }
+ if (!isReplace || !retainImplicitGrantOnReplace) {
+ synchronized (mImplicitlyQueryableLock) {
+ for (int u = 0; u < userCount; u++) {
+ final int userId = users[u].id;
+ final int removingUid = UserHandle.getUid(userId, setting.getAppId());
+ mImplicitlyQueryable.remove(removingUid);
+ for (int i = mImplicitlyQueryable.size() - 1; i >= 0; i--) {
+ mImplicitlyQueryable.remove(mImplicitlyQueryable.keyAt(i),
+ removingUid);
+ }
- if (isReplace) {
- continue;
- }
+ if (isReplace) {
+ continue;
+ }
- mRetainedImplicitlyQueryable.remove(removingUid);
- for (int i = mRetainedImplicitlyQueryable.size() - 1; i >= 0; i--) {
- mRetainedImplicitlyQueryable.remove(
- mRetainedImplicitlyQueryable.keyAt(i), removingUid);
+ mRetainedImplicitlyQueryable.remove(removingUid);
+ for (int i = mRetainedImplicitlyQueryable.size() - 1; i >= 0; i--) {
+ mRetainedImplicitlyQueryable.remove(
+ mRetainedImplicitlyQueryable.keyAt(i), removingUid);
+ }
}
}
}
diff --git a/services/core/java/com/android/server/pm/BackgroundDexOptService.java b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
index e7412c5..d856d54 100644
--- a/services/core/java/com/android/server/pm/BackgroundDexOptService.java
+++ b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
@@ -410,7 +410,7 @@
job.jobFinished(params, !completed);
} else {
// Periodic job
- job.jobFinished(params, true);
+ job.jobFinished(params, false /* reschedule */);
}
markDexOptCompleted();
}
diff --git a/services/core/java/com/android/server/pm/ComputerEngine.java b/services/core/java/com/android/server/pm/ComputerEngine.java
index b9967f9..d381e32 100644
--- a/services/core/java/com/android/server/pm/ComputerEngine.java
+++ b/services/core/java/com/android/server/pm/ComputerEngine.java
@@ -63,7 +63,6 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
-import android.apex.ApexInfo;
import android.app.ActivityManager;
import android.content.ComponentName;
import android.content.Context;
@@ -112,6 +111,7 @@
import android.util.LongSparseLongArray;
import android.util.MathUtils;
import android.util.Pair;
+import android.util.PrintWriterPrinter;
import android.util.Slog;
import android.util.SparseArray;
import android.util.Xml;
@@ -396,7 +396,6 @@
private final UserManagerService mUserManager;
private final PermissionManagerServiceInternal mPermissionManager;
private final ApexManager mApexManager;
- private final ApexPackageInfo mApexPackageInfo;
private final PackageManagerServiceInjector mInjector;
private final ComponentResolverApi mComponentResolver;
private final InstantAppResolverConnection mInstantAppResolverConnection;
@@ -452,7 +451,6 @@
mContext = args.service.mContext;
mInjector = args.service.mInjector;
mApexManager = args.service.mApexManager;
- mApexPackageInfo = args.service.mApexPackageInfo;
mInstantAppResolverConnection = args.service.mInstantAppResolverConnection;
mDefaultAppProvider = args.service.getDefaultAppProvider();
mDomainVerificationManager = args.service.mDomainVerificationManager;
@@ -968,10 +966,8 @@
if (p != null) {
PackageStateInternal ps = mSettings.getPackage(packageName);
if (ps == null) return null;
- if (ApexPackageInfo.ENABLE_FEATURE_SCAN_APEX) {
- if (!matchApex && p.isApex()) {
- return null;
- }
+ if (!matchApex && p.isApex()) {
+ return null;
}
if (filterSharedLibPackage(ps, filterCallingUid, userId, flags)) {
return null;
@@ -987,24 +983,6 @@
}
return ai;
}
- if (!ApexPackageInfo.ENABLE_FEATURE_SCAN_APEX) {
- if (matchApex) {
- // For APKs, PackageInfo.applicationInfo is not exactly the same as ApplicationInfo
- // returned from getApplicationInfo, but for APEX packages difference shouldn't be
- // very big.
- // TODO(b/155328545): generate proper application info for APEXes as well.
- int apexFlags = ApexManager.MATCH_ACTIVE_PACKAGE;
- if ((flags & PackageManager.MATCH_SYSTEM_ONLY) != 0) {
- apexFlags = ApexManager.MATCH_FACTORY_PACKAGE;
- }
- final var pair = mApexPackageInfo.getPackageInfo(packageName, apexFlags);
- if (pair == null) {
- return null;
- }
- return PackageInfoUtils.generateApplicationInfo(pair.second, flags,
- PackageUserStateInternal.DEFAULT, userId, null);
- }
- }
if ("android".equals(packageName) || "system".equals(packageName)) {
return androidApplication();
}
@@ -1553,22 +1531,10 @@
final boolean matchApex = (flags & MATCH_APEX) != 0;
if (matchFactoryOnly) {
// Instant app filtering for APEX modules is ignored
- if (!ApexPackageInfo.ENABLE_FEATURE_SCAN_APEX) {
- if (matchApex) {
- final var pair = mApexPackageInfo.getPackageInfo(packageName,
- ApexManager.MATCH_FACTORY_PACKAGE);
- if (pair == null) {
- return null;
- }
- return PackageInfoUtils.generate(pair.second, pair.first, flags, null, userId);
- }
- }
final PackageStateInternal ps = mSettings.getDisabledSystemPkg(packageName);
if (ps != null) {
- if (ApexPackageInfo.ENABLE_FEATURE_SCAN_APEX) {
- if (!matchApex && ps.getPkg() != null && ps.getPkg().isApex()) {
- return null;
- }
+ if (!matchApex && ps.getPkg() != null && ps.getPkg().isApex()) {
+ return null;
}
if (filterSharedLibPackage(ps, filterCallingUid, userId, flags)) {
return null;
@@ -1589,10 +1555,8 @@
}
if (p != null) {
final PackageStateInternal ps = getPackageStateInternal(p.getPackageName());
- if (ApexPackageInfo.ENABLE_FEATURE_SCAN_APEX) {
- if (!matchApex && p.isApex()) {
- return null;
- }
+ if (!matchApex && p.isApex()) {
+ return null;
}
if (filterSharedLibPackage(ps, filterCallingUid, userId, flags)) {
return null;
@@ -1614,16 +1578,6 @@
}
return generatePackageInfo(ps, flags, userId);
}
- if (!ApexPackageInfo.ENABLE_FEATURE_SCAN_APEX) {
- if (matchApex) {
- final var pair = mApexPackageInfo.getPackageInfo(packageName,
- ApexManager.MATCH_ACTIVE_PACKAGE);
- if (pair == null) {
- return null;
- }
- return PackageInfoUtils.generate(pair.second, pair.first, flags, null, userId);
- }
- }
return null;
}
@@ -1692,10 +1646,8 @@
ps = psDisabled;
}
}
- if (ApexPackageInfo.ENABLE_FEATURE_SCAN_APEX) {
- if (!listApex && ps.getPkg() != null && ps.getPkg().isApex()) {
- continue;
- }
+ if (!listApex && ps.getPkg() != null && ps.getPkg().isApex()) {
+ continue;
}
if (filterSharedLibPackage(ps, callingUid, userId, flags)) {
continue;
@@ -1722,10 +1674,8 @@
ps = psDisabled;
}
}
- if (ApexPackageInfo.ENABLE_FEATURE_SCAN_APEX) {
- if (!listApex && p.isApex()) {
- continue;
- }
+ if (!listApex && p.isApex()) {
+ continue;
}
if (filterSharedLibPackage(ps, callingUid, userId, flags)) {
continue;
@@ -1739,22 +1689,6 @@
}
}
}
- if (!ApexPackageInfo.ENABLE_FEATURE_SCAN_APEX) {
- if (listApex) {
- List<Pair<ApexInfo, AndroidPackage>> pairs;
- if (listFactory) {
- pairs = mApexPackageInfo.getFactoryPackages();
- } else {
- pairs = mApexPackageInfo.getActivePackages();
- }
-
- for (int index = 0; index < pairs.size(); index++) {
- var pair = pairs.get(index);
- list.add(PackageInfoUtils.generate(pair.second, pair.first, flags, null,
- userId));
- }
- }
- }
return new ParceledListSlice<>(list);
}
@@ -3155,24 +3089,56 @@
}
private void dumpApex(PrintWriter pw, String packageName) {
- if (ApexPackageInfo.ENABLE_FEATURE_SCAN_APEX) {
- final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ", 120);
- List<PackageStateInternal> activePackages = new ArrayList<>();
- List<PackageStateInternal> inactivePackages = new ArrayList<>();
- List<PackageStateInternal> factoryActivePackages = new ArrayList<>();
- List<PackageStateInternal> factoryInactivePackages = new ArrayList<>();
- generateApexPackageInfo(activePackages, inactivePackages, factoryActivePackages,
- factoryInactivePackages);
- ipw.println("Active APEX packages:");
- ApexPackageInfo.dumpPackageStates(activePackages, true, packageName, ipw);
- ipw.println("Inactive APEX packages:");
- ApexPackageInfo.dumpPackageStates(inactivePackages, false, packageName, ipw);
- ipw.println("Factory APEX packages:");
- ApexPackageInfo.dumpPackageStates(factoryActivePackages, true, packageName, ipw);
- ApexPackageInfo.dumpPackageStates(factoryInactivePackages, false, packageName, ipw);
- } else {
- mApexPackageInfo.dump(pw, packageName);
+ final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ", 120);
+ List<PackageStateInternal> activePackages = new ArrayList<>();
+ List<PackageStateInternal> inactivePackages = new ArrayList<>();
+ List<PackageStateInternal> factoryActivePackages = new ArrayList<>();
+ List<PackageStateInternal> factoryInactivePackages = new ArrayList<>();
+ generateApexPackageInfo(activePackages, inactivePackages, factoryActivePackages,
+ factoryInactivePackages);
+ ipw.println("Active APEX packages:");
+ dumpApexPackageStates(activePackages, true, packageName, ipw);
+ ipw.println("Inactive APEX packages:");
+ dumpApexPackageStates(inactivePackages, false, packageName, ipw);
+ ipw.println("Factory APEX packages:");
+ dumpApexPackageStates(factoryActivePackages, true, packageName, ipw);
+ dumpApexPackageStates(factoryInactivePackages, false, packageName, ipw);
+ }
+
+
+ /**
+ * Dump information about the packages contained in a particular cache
+ * @param packageStates the states to print information about.
+ * @param packageName a {@link String} containing a package name, or {@code null}. If set,
+ * only information about that specific package will be dumped.
+ * @param ipw the {@link IndentingPrintWriter} object to send information to.
+ */
+ private static void dumpApexPackageStates(List<PackageStateInternal> packageStates,
+ boolean isActive, @Nullable String packageName, IndentingPrintWriter ipw) {
+ ipw.println();
+ ipw.increaseIndent();
+ for (int i = 0, size = packageStates.size(); i < size; i++) {
+ final var packageState = packageStates.get(i);
+ var pkg = packageState.getPkg();
+ if (packageName != null && !packageName.equals(pkg.getPackageName())) {
+ continue;
+ }
+ ipw.println(pkg.getPackageName());
+ ipw.increaseIndent();
+ ipw.println("Version: " + pkg.getLongVersionCode());
+ ipw.println("Path: " + pkg.getBaseApkPath());
+ ipw.println("IsActive: " + isActive);
+ ipw.println("IsFactory: " + !packageState.isUpdatedSystemApp());
+ ipw.println("ApplicationInfo: ");
+ ipw.increaseIndent();
+ // TODO: Dump the package manually
+ AndroidPackageUtils.generateAppInfoWithoutState(pkg)
+ .dump(new PrintWriterPrinter(ipw), "");
+ ipw.decreaseIndent();
+ ipw.decreaseIndent();
}
+ ipw.decreaseIndent();
+ ipw.println();
}
// The body of findPreferredActivity.
@@ -3551,12 +3517,8 @@
@Override
public boolean isApexPackage(String packageName) {
- if (!ApexPackageInfo.ENABLE_FEATURE_SCAN_APEX) {
- return mApexPackageInfo.isApexPackage(packageName);
- } else {
- final AndroidPackage pkg = mPackages.get(packageName);
- return pkg != null && pkg.isApex();
- }
+ final AndroidPackage pkg = mPackages.get(packageName);
+ return pkg != null && pkg.isApex();
}
@Override
@@ -4563,10 +4525,8 @@
effectiveFlags |= PackageManager.MATCH_ANY_USER;
}
if (ps.getPkg() != null) {
- if (ApexPackageInfo.ENABLE_FEATURE_SCAN_APEX) {
- if (!listApex && ps.getPkg().isApex()) {
- continue;
- }
+ if (!listApex && ps.getPkg().isApex()) {
+ continue;
}
if (filterSharedLibPackage(ps, callingUid, userId, flags)) {
continue;
@@ -4596,10 +4556,8 @@
if (pkg == null) {
continue;
}
- if (ApexPackageInfo.ENABLE_FEATURE_SCAN_APEX) {
- if (!listApex && pkg.isApex()) {
- continue;
- }
+ if (!listApex && pkg.isApex()) {
+ continue;
}
if (filterSharedLibPackage(packageState, Binder.getCallingUid(), userId, flags)) {
continue;
diff --git a/services/core/java/com/android/server/pm/InitAppsHelper.java b/services/core/java/com/android/server/pm/InitAppsHelper.java
index 6f59096..12b5ab8 100644
--- a/services/core/java/com/android/server/pm/InitAppsHelper.java
+++ b/services/core/java/com/android/server/pm/InitAppsHelper.java
@@ -72,7 +72,6 @@
private final int mSystemScanFlags;
private final InstallPackageHelper mInstallPackageHelper;
private final ApexManager mApexManager;
- private final ApexPackageInfo mApexPackageInfo;
private final ExecutorService mExecutorService;
/* Tracks how long system scan took */
private long mSystemScanTime;
@@ -96,13 +95,11 @@
private final List<String> mStubSystemApps = new ArrayList<>();
// TODO(b/198166813): remove PMS dependency
- InitAppsHelper(PackageManagerService pm,
- ApexManager apexManager, ApexPackageInfo apexPackageInfo,
+ InitAppsHelper(PackageManagerService pm, ApexManager apexManager,
InstallPackageHelper installPackageHelper,
List<ScanPartition> systemPartitions) {
mPm = pm;
mApexManager = apexManager;
- mApexPackageInfo = apexPackageInfo;
mInstallPackageHelper = installPackageHelper;
mSystemPartitions = systemPartitions;
mDirsToScanAsSystem = getSystemScanPartitions();
@@ -165,16 +162,8 @@
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanApexPackages");
try {
- final List<ApexManager.ScanResult> apexScanResults;
- if (ApexPackageInfo.ENABLE_FEATURE_SCAN_APEX) {
- apexScanResults = mInstallPackageHelper.scanApexPackages(
- mApexManager.getAllApexInfos(), mSystemParseFlags, mSystemScanFlags,
- packageParser, mExecutorService);
- } else {
- apexScanResults = mApexPackageInfo.scanApexPackages(
- mApexManager.getAllApexInfos(), packageParser, mExecutorService);
- }
- return apexScanResults;
+ return mInstallPackageHelper.scanApexPackages(mApexManager.getAllApexInfos(),
+ mSystemParseFlags, mSystemScanFlags, packageParser, mExecutorService);
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java
index 9d007c9..7ea0c04 100644
--- a/services/core/java/com/android/server/pm/InstallPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java
@@ -463,7 +463,8 @@
final Computer snapshot = mPm.snapshotComputer();
mPm.mComponentResolver.addAllComponents(pkg, chatty, mPm.mSetupWizardPackage, snapshot);
- mPm.mAppsFilter.addPackage(snapshot, pkgSetting, isReplace);
+ mPm.mAppsFilter.addPackage(snapshot, pkgSetting, isReplace,
+ (scanFlags & SCAN_DONT_KILL_APP) != 0 /* retainImplicitGrantOnReplace */);
mPm.addAllPackageProperties(pkg);
if (oldPkgSetting == null || oldPkgSetting.getPkg() == null) {
diff --git a/services/core/java/com/android/server/pm/InstallingSession.java b/services/core/java/com/android/server/pm/InstallingSession.java
index 16b3a81..88469f5 100644
--- a/services/core/java/com/android/server/pm/InstallingSession.java
+++ b/services/core/java/com/android/server/pm/InstallingSession.java
@@ -572,19 +572,15 @@
}
try (PackageParser2 packageParser = mPm.mInjector.getScanningPackageParser()) {
ApexInfo apexInfo = mPm.mApexManager.installPackage(apexes[0]);
- if (ApexPackageInfo.ENABLE_FEATURE_SCAN_APEX) {
- // APEX has been handled successfully by apexd. Let's continue the install flow
- // so it will be scanned and registered with the system.
- // TODO(b/225756739): Improve atomicity of rebootless APEX install.
- // The newly installed APEX will not be reverted even if
- // processApkInstallRequests() fails. Need a way to keep info stored in apexd
- // and PMS in sync in the face of install failures.
- request.setApexInfo(apexInfo);
- mPm.mHandler.post(() -> processApkInstallRequests(true, requests));
- return;
- } else {
- mPm.mApexPackageInfo.notifyPackageInstalled(apexInfo, packageParser);
- }
+ // APEX has been handled successfully by apexd. Let's continue the install flow
+ // so it will be scanned and registered with the system.
+ // TODO(b/225756739): Improve atomicity of rebootless APEX install.
+ // The newly installed APEX will not be reverted even if
+ // processApkInstallRequests() fails. Need a way to keep info stored in apexd
+ // and PMS in sync in the face of install failures.
+ request.setApexInfo(apexInfo);
+ mPm.mHandler.post(() -> processApkInstallRequests(true, requests));
+ return;
}
} catch (PackageManagerException e) {
request.setError("APEX installation failed", e);
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 5df73a6..72ec510 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -2763,10 +2763,11 @@
"Missing existing base package");
}
- // Default to require only if existing base apk has fs-verity.
+ // Default to require only if existing base apk has fs-verity signature.
mVerityFoundForApks = PackageManagerServiceUtils.isApkVerityEnabled()
&& params.mode == SessionParams.MODE_INHERIT_EXISTING
- && VerityUtils.hasFsverity(pkgInfo.applicationInfo.getBaseCodePath());
+ && (new File(VerityUtils.getFsveritySignatureFilePath(
+ pkgInfo.applicationInfo.getBaseCodePath()))).exists();
final List<File> removedFiles = getRemovedFilesLocked();
final List<String> removeSplitList = new ArrayList<>();
@@ -3326,7 +3327,7 @@
"Failure to obtain package info.");
}
final List<String> filePaths = packageLite.getAllApkPaths();
- final String appLabel = mPreapprovalDetails.getLabel();
+ final CharSequence appLabel = mPreapprovalDetails.getLabel();
final ULocale appLocale = mPreapprovalDetails.getLocale();
final ApplicationInfo appInfo = packageInfo.applicationInfo;
boolean appLabelMatched = false;
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index a98247c..b302d4a 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -691,7 +691,6 @@
private final ModuleInfoProvider mModuleInfoProvider;
final ApexManager mApexManager;
- final ApexPackageInfo mApexPackageInfo;
final PackageManagerServiceInjector mInjector;
@@ -1642,7 +1641,6 @@
mSharedLibraries = injector.getSharedLibrariesImpl();
mApexManager = testParams.apexManager;
- mApexPackageInfo = new ApexPackageInfo(this);
mArtManagerService = testParams.artManagerService;
mAvailableFeatures = testParams.availableFeatures;
mBackgroundDexOptService = testParams.backgroundDexOptService;
@@ -1842,7 +1840,6 @@
mProtectedPackages = new ProtectedPackages(mContext);
mApexManager = injector.getApexManager();
- mApexPackageInfo = new ApexPackageInfo(this);
mAppsFilter = mInjector.getAppsFilter();
mInstantAppRegistry = new InstantAppRegistry(mContext, mPermissionManager,
@@ -1980,8 +1977,8 @@
+ ver.fingerprint + " to " + PackagePartitions.FINGERPRINT);
}
- mInitAppsHelper = new InitAppsHelper(this, mApexManager, mApexPackageInfo,
- mInstallPackageHelper, mInjector.getSystemPartitions());
+ mInitAppsHelper = new InitAppsHelper(this, mApexManager, mInstallPackageHelper,
+ mInjector.getSystemPartitions());
// when upgrading from pre-M, promote system app permissions from install to runtime
mPromoteSystemApps =
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 12c9d4b..45c0d6e 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -455,19 +455,24 @@
// The user's preferred activities associated with particular intent
// filters.
@Watched
- private final WatchedSparseArray<PreferredIntentResolver>
- mPreferredActivities = new WatchedSparseArray<>();
+ private final WatchedSparseArray<PreferredIntentResolver> mPreferredActivities;
+ private final SnapshotCache<WatchedSparseArray<PreferredIntentResolver>>
+ mPreferredActivitiesSnapshot;
// The persistent preferred activities of the user's profile/device owner
// associated with particular intent filters.
@Watched
private final WatchedSparseArray<PersistentPreferredIntentResolver>
- mPersistentPreferredActivities = new WatchedSparseArray<>();
+ mPersistentPreferredActivities;
+ private final SnapshotCache<WatchedSparseArray<PersistentPreferredIntentResolver>>
+ mPersistentPreferredActivitiesSnapshot;
+
// For every user, it is used to find to which other users the intent can be forwarded.
@Watched
- private final WatchedSparseArray<CrossProfileIntentResolver>
- mCrossProfileIntentResolvers = new WatchedSparseArray<>();
+ private final WatchedSparseArray<CrossProfileIntentResolver> mCrossProfileIntentResolvers;
+ private final SnapshotCache<WatchedSparseArray<CrossProfileIntentResolver>>
+ mCrossProfileIntentResolversSnapshot;
@Watched
final WatchedArrayMap<String, SharedUserSetting> mSharedUsers = new WatchedArrayMap<>();
@@ -476,11 +481,12 @@
// For reading/writing settings file.
@Watched
- private final WatchedArrayList<Signature> mPastSignatures =
- new WatchedArrayList<Signature>();
+ private final WatchedArrayList<Signature> mPastSignatures;
+ private final SnapshotCache<WatchedArrayList<Signature>> mPastSignaturesSnapshot;
+
@Watched
- private final WatchedArrayMap<Long, Integer> mKeySetRefs =
- new WatchedArrayMap<Long, Integer>();
+ 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
@@ -511,7 +517,8 @@
* scanning to make it less confusing.
*/
@Watched
- private final WatchedArrayList<PackageSetting> mPendingPackages = new WatchedArrayList<>();
+ private final WatchedArrayList<PackageSetting> mPendingPackages;
+ private final SnapshotCache<WatchedArrayList<PackageSetting>> mPendingPackagesSnapshot;
private final File mSystemDir;
@@ -583,6 +590,26 @@
mInstallerPackagesSnapshot =
new SnapshotCache.Auto<>(mInstallerPackages, mInstallerPackages,
"Settings.mInstallerPackages");
+ mPreferredActivities = new WatchedSparseArray<>();
+ mPreferredActivitiesSnapshot = new SnapshotCache.Auto<>(mPreferredActivities,
+ mPreferredActivities, "Settings.mPreferredActivities");
+ mPersistentPreferredActivities = new WatchedSparseArray<>();
+ mPersistentPreferredActivitiesSnapshot = new SnapshotCache.Auto<>(
+ mPersistentPreferredActivities, mPersistentPreferredActivities,
+ "Settings.mPersistentPreferredActivities");
+ mCrossProfileIntentResolvers = new WatchedSparseArray<>();
+ 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");
mKeySetManagerService = new KeySetManagerService(mPackages);
// Test-only handler working on background thread.
@@ -623,6 +650,26 @@
mInstallerPackagesSnapshot =
new SnapshotCache.Auto<>(mInstallerPackages, mInstallerPackages,
"Settings.mInstallerPackages");
+ mPreferredActivities = new WatchedSparseArray<>();
+ mPreferredActivitiesSnapshot = new SnapshotCache.Auto<>(mPreferredActivities,
+ mPreferredActivities, "Settings.mPreferredActivities");
+ mPersistentPreferredActivities = new WatchedSparseArray<>();
+ mPersistentPreferredActivitiesSnapshot = new SnapshotCache.Auto<>(
+ mPersistentPreferredActivities, mPersistentPreferredActivities,
+ "Settings.mPersistentPreferredActivities");
+ mCrossProfileIntentResolvers = new WatchedSparseArray<>();
+ 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");
mKeySetManagerService = new KeySetManagerService(mPackages);
mHandler = handler;
@@ -699,24 +746,27 @@
mBlockUninstallPackages.snapshot(r.mBlockUninstallPackages);
mVersion.putAll(r.mVersion);
mVerifierDeviceIdentity = r.mVerifierDeviceIdentity;
- WatchedSparseArray.snapshot(
- mPreferredActivities, r.mPreferredActivities);
- WatchedSparseArray.snapshot(
- mPersistentPreferredActivities, r.mPersistentPreferredActivities);
- WatchedSparseArray.snapshot(
- mCrossProfileIntentResolvers, r.mCrossProfileIntentResolvers);
+ mPreferredActivities = r.mPreferredActivitiesSnapshot.snapshot();
+ mPreferredActivitiesSnapshot = new SnapshotCache.Sealed<>();
+ mPersistentPreferredActivities = r.mPersistentPreferredActivitiesSnapshot.snapshot();
+ mPersistentPreferredActivitiesSnapshot = new SnapshotCache.Sealed<>();
+ mCrossProfileIntentResolvers = r.mCrossProfileIntentResolversSnapshot.snapshot();
+ mCrossProfileIntentResolversSnapshot = new SnapshotCache.Sealed<>();
+
mSharedUsers.snapshot(r.mSharedUsers);
mAppIds = r.mAppIds.snapshot();
- WatchedArrayList.snapshot(
- mPastSignatures, r.mPastSignatures);
- WatchedArrayMap.snapshot(
- mKeySetRefs, r.mKeySetRefs);
+
+ mPastSignatures = r.mPastSignaturesSnapshot.snapshot();
+ mPastSignaturesSnapshot = new SnapshotCache.Sealed<>();
+ mKeySetRefs = r.mKeySetRefsSnapshot.snapshot();
+ mKeySetRefsSnapshot = new SnapshotCache.Sealed<>();
+
mRenamedPackages.snapshot(r.mRenamedPackages);
mNextAppLinkGeneration.snapshot(r.mNextAppLinkGeneration);
mDefaultBrowserApp.snapshot(r.mDefaultBrowserApp);
// mReadMessages
- WatchedArrayList.snapshot(
- mPendingPackages, r.mPendingPackages);
+ mPendingPackages = r.mPendingPackagesSnapshot.snapshot();
+ mPendingPackagesSnapshot = new SnapshotCache.Sealed<>();
mSystemDir = null;
// mKeySetManagerService;
mPermissions = r.mPermissions;
diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
index d1f3341e..dbd026e 100644
--- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
+++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
@@ -147,7 +147,8 @@
UserManager.DISALLOW_WIFI_TETHERING,
UserManager.DISALLOW_SHARING_ADMIN_CONFIGURED_WIFI,
UserManager.DISALLOW_WIFI_DIRECT,
- UserManager.DISALLOW_ADD_WIFI_CONFIG
+ UserManager.DISALLOW_ADD_WIFI_CONFIG,
+ UserManager.DISALLOW_CELLULAR_2G
});
public static final Set<String> DEPRECATED_USER_RESTRICTIONS = Sets.newArraySet(
@@ -195,7 +196,8 @@
UserManager.DISALLOW_CHANGE_WIFI_STATE,
UserManager.DISALLOW_WIFI_TETHERING,
UserManager.DISALLOW_WIFI_DIRECT,
- UserManager.DISALLOW_ADD_WIFI_CONFIG
+ UserManager.DISALLOW_ADD_WIFI_CONFIG,
+ UserManager.DISALLOW_CELLULAR_2G
);
/**
@@ -234,7 +236,8 @@
UserManager.DISALLOW_CHANGE_WIFI_STATE,
UserManager.DISALLOW_WIFI_TETHERING,
UserManager.DISALLOW_WIFI_DIRECT,
- UserManager.DISALLOW_ADD_WIFI_CONFIG
+ UserManager.DISALLOW_ADD_WIFI_CONFIG,
+ UserManager.DISALLOW_CELLULAR_2G
);
/**
diff --git a/services/core/java/com/android/server/power/stats/CpuWakeupStats.java b/services/core/java/com/android/server/power/stats/CpuWakeupStats.java
index 5f76fbc..79e35c2 100644
--- a/services/core/java/com/android/server/power/stats/CpuWakeupStats.java
+++ b/services/core/java/com/android/server/power/stats/CpuWakeupStats.java
@@ -384,7 +384,7 @@
private static final class Wakeup {
private static final String PARSER_TAG = "CpuWakeupStats.Wakeup";
private static final String ABORT_REASON_PREFIX = "Abort";
- private static final Pattern sIrqPattern = Pattern.compile("(\\d+)\\s+(\\S+)");
+ private static final Pattern sIrqPattern = Pattern.compile("^(\\d+)\\s+(\\S+)");
String mRawReason;
long mElapsedMillis;
@@ -409,7 +409,7 @@
IrqDevice[] parsedDevices = new IrqDevice[components.length];
for (String component : components) {
- final Matcher matcher = sIrqPattern.matcher(component);
+ final Matcher matcher = sIrqPattern.matcher(component.trim());
if (matcher.find()) {
final int line;
final String device;
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index d378b11..c59b90f 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -16,12 +16,15 @@
package com.android.server.statusbar;
+import static android.Manifest.permission.INTERACT_ACROSS_USERS;
+import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
import static android.app.StatusBarManager.DISABLE2_GLOBAL_ACTIONS;
import static android.app.StatusBarManager.DISABLE2_NOTIFICATION_SHADE;
import static android.app.StatusBarManager.NAV_BAR_MODE_DEFAULT;
import static android.app.StatusBarManager.NAV_BAR_MODE_KIDS;
import static android.app.StatusBarManager.NavBarMode;
import static android.app.StatusBarManager.SessionFlags;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY;
@@ -1304,18 +1307,23 @@
"StatusBarManagerService");
}
+ private boolean doesCallerHoldInteractAcrossUserPermission() {
+ return mContext.checkCallingPermission(INTERACT_ACROSS_USERS_FULL) == PERMISSION_GRANTED
+ || mContext.checkCallingPermission(INTERACT_ACROSS_USERS) == PERMISSION_GRANTED;
+ }
+
/**
* For targetSdk S+ we require STATUS_BAR. For targetSdk < S, we only require EXPAND_STATUS_BAR
* but also require that it falls into one of the allowed use-cases to lock down abuse vector.
*/
private boolean checkCanCollapseStatusBar(String method) {
int uid = Binder.getCallingUid();
- int pid = Binder.getCallingUid();
+ int pid = Binder.getCallingPid();
if (CompatChanges.isChangeEnabled(LOCK_DOWN_COLLAPSE_STATUS_BAR, uid)) {
enforceStatusBar();
} else {
if (mContext.checkPermission(Manifest.permission.STATUS_BAR, pid, uid)
- != PackageManager.PERMISSION_GRANTED) {
+ != PERMISSION_GRANTED) {
enforceExpandStatusBar();
if (!mActivityTaskManager.canCloseSystemDialogs(pid, uid)) {
Slog.e(TAG, "Permission Denial: Method " + method + "() requires permission "
@@ -2021,6 +2029,11 @@
}
final int userId = mCurrentUserId;
+ final int callingUserId = UserHandle.getUserId(Binder.getCallingUid());
+ if (mCurrentUserId != callingUserId && !doesCallerHoldInteractAcrossUserPermission()) {
+ throw new SecurityException("Calling user id: " + callingUserId
+ + ", cannot call on behalf of current user id: " + mCurrentUserId + ".");
+ }
final long userIdentity = Binder.clearCallingIdentity();
try {
Settings.Secure.putIntForUser(mContext.getContentResolver(),
diff --git a/services/core/java/com/android/server/utils/EventLogger.java b/services/core/java/com/android/server/utils/EventLogger.java
index 11766a3..770cb72 100644
--- a/services/core/java/com/android/server/utils/EventLogger.java
+++ b/services/core/java/com/android/server/utils/EventLogger.java
@@ -26,7 +26,9 @@
import java.lang.annotation.RetentionPolicy;
import java.text.SimpleDateFormat;
import java.util.ArrayDeque;
+import java.util.ArrayList;
import java.util.Date;
+import java.util.List;
import java.util.Locale;
/**
@@ -79,20 +81,34 @@
enqueue(event.printLog(logType, tag));
}
+ /** Dumps events into the given {@link DumpSink}. */
+ public synchronized void dump(DumpSink dumpSink) {
+ dumpSink.sink(mTag, new ArrayList<>(mEvents));
+ }
+
/** Dumps events using {@link PrintWriter}. */
public synchronized void dump(PrintWriter pw) {
dump(pw, "" /* prefix */);
}
/** Dumps events using {@link PrintWriter} with a certain indent. */
- public synchronized void dump(PrintWriter pw, String prefix) {
- pw.println(prefix + "Events log: " + mTag);
- String indent = prefix + " ";
+ public synchronized void dump(PrintWriter pw, String indent) {
+ pw.println(indent + "Events log: " + mTag);
+
+ String childrenIndention = indent + " ";
for (Event evt : mEvents) {
- pw.println(indent + evt.toString());
+ pw.println(childrenIndention + evt.toString());
}
}
+ /** Receives events from {@link EventLogger} upon a {@link #dump(DumpSink)} call. **/
+ public interface DumpSink {
+
+ /** Processes given events into some pipeline with a given tag. **/
+ void sink(String tag, List<Event> events);
+
+ }
+
public abstract static class Event {
/** Timestamps formatter. */
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index abb57bc..6a35533 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -320,9 +320,7 @@
IRemoteCallback.Stub callback = new IRemoteCallback.Stub() {
@Override
public void sendResult(Bundle data) throws RemoteException {
- if (DEBUG) {
- Slog.d(TAG, "publish system wallpaper changed!");
- }
+ Slog.d(TAG, "publish system wallpaper changed!");
notifyWallpaperChanged(wallpaper);
}
};
@@ -1552,6 +1550,7 @@
mReply.sendResult(null);
} catch (RemoteException e) {
Binder.restoreCallingIdentity(ident);
+ Slog.d(TAG, "failed to send callback!", e);
}
mReply = null;
}
diff --git a/services/core/java/com/android/server/wm/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java
index b9fa80c..7e56dbf 100644
--- a/services/core/java/com/android/server/wm/InsetsPolicy.java
+++ b/services/core/java/com/android/server/wm/InsetsPolicy.java
@@ -26,7 +26,6 @@
import static android.view.InsetsController.ANIMATION_TYPE_SHOW;
import static android.view.InsetsController.LAYOUT_INSETS_DURING_ANIMATION_HIDDEN;
import static android.view.InsetsController.LAYOUT_INSETS_DURING_ANIMATION_SHOWN;
-import static android.view.InsetsState.ITYPE_CAPTION_BAR;
import static android.view.InsetsState.ITYPE_CLIMATE_BAR;
import static android.view.InsetsState.ITYPE_EXTRA_NAVIGATION_BAR;
import static android.view.InsetsState.ITYPE_IME;
@@ -289,9 +288,8 @@
final boolean alwaysOnTop = token != null && token.isAlwaysOnTop();
// Always use windowing mode fullscreen when get insets for window metrics to make sure it
// contains all insets types.
- final InsetsState originalState = mDisplayContent.getInsetsPolicy()
- .enforceInsetsPolicyForTarget(type, WINDOWING_MODE_FULLSCREEN, alwaysOnTop,
- attrs.type, mStateController.getRawInsetsState());
+ final InsetsState originalState = enforceInsetsPolicyForTarget(WINDOWING_MODE_FULLSCREEN,
+ alwaysOnTop, attrs, mStateController.getRawInsetsState());
InsetsState state = adjustVisibilityForTransientTypes(originalState);
return adjustInsetsForRoundedCorners(token, state, state == originalState);
}
@@ -343,56 +341,42 @@
/**
- * Modifies the given {@code state} according to the {@code type} (Inset type) provided by
- * the target.
- * When performing layout of the target or dispatching insets to the target, we need to exclude
- * sources which should not be visible to the target. e.g., the source which represents the
- * target window itself, and the IME source when the target is above IME. We also need to
- * exclude certain types of insets source for client within specific windowing modes.
+ * Modifies the given {@code state} according to the target's window state.
+ * When performing layout of the target or dispatching insets to the target, we need to adjust
+ * sources based on the target. e.g., the floating window will not receive system bars other
+ * than caption, and some insets provider may request to override sizes for given window types.
+ * Since the window type and the insets types provided by the window shall not change at
+ * runtime, rotation doesn't matter in the layout params.
*
- * @param type the inset type provided by the target
* @param windowingMode the windowing mode of the target
* @param isAlwaysOnTop is the target always on top
- * @param windowType the type of the target
+ * @param attrs the layout params of the target
* @param state the input inset state containing all the sources
* @return The state stripped of the necessary information.
*/
- InsetsState enforceInsetsPolicyForTarget(@InternalInsetsType int type,
- @WindowConfiguration.WindowingMode int windowingMode, boolean isAlwaysOnTop,
- int windowType, InsetsState state) {
+ InsetsState enforceInsetsPolicyForTarget(@WindowConfiguration.WindowingMode int windowingMode,
+ boolean isAlwaysOnTop, WindowManager.LayoutParams attrs, InsetsState state) {
boolean stateCopied = false;
- if (type != ITYPE_INVALID) {
+ if (attrs.providedInsets != null && attrs.providedInsets.length > 0) {
state = new InsetsState(state);
stateCopied = true;
- state.removeSource(type);
-
- // Navigation bar doesn't get influenced by anything else
- if (type == ITYPE_NAVIGATION_BAR || type == ITYPE_EXTRA_NAVIGATION_BAR) {
- state.removeSource(ITYPE_STATUS_BAR);
- state.removeSource(ITYPE_CLIMATE_BAR);
- state.removeSource(ITYPE_CAPTION_BAR);
- state.removeSource(ITYPE_NAVIGATION_BAR);
- state.removeSource(ITYPE_EXTRA_NAVIGATION_BAR);
- }
-
- // Status bar doesn't get influenced by caption bar
- if (type == ITYPE_STATUS_BAR || type == ITYPE_CLIMATE_BAR) {
- state.removeSource(ITYPE_CAPTION_BAR);
+ for (int i = attrs.providedInsets.length - 1; i >= 0; i--) {
+ state.removeSource(attrs.providedInsets[i].type);
}
}
ArrayMap<Integer, WindowContainerInsetsSourceProvider> providers = mStateController
.getSourceProviders();
for (int i = providers.size() - 1; i >= 0; i--) {
WindowContainerInsetsSourceProvider otherProvider = providers.valueAt(i);
- if (otherProvider.overridesFrame(windowType)) {
+ if (otherProvider.overridesFrame(attrs.type)) {
if (!stateCopied) {
state = new InsetsState(state);
stateCopied = true;
}
InsetsSource override =
new InsetsSource(state.getSource(otherProvider.getSource().getType()));
- override.setFrame(otherProvider.getOverriddenFrame(windowType));
+ override.setFrame(otherProvider.getOverriddenFrame(attrs.type));
state.addSource(override);
}
}
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index 80c9803..a64bd69 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -469,6 +469,48 @@
}
/**
+ * Records that a particular container has been reparented. This only effects windows that have
+ * already been collected in the transition. This should be called before reparenting because
+ * the old parent may be removed during reparenting, for example:
+ * {@link Task#shouldRemoveSelfOnLastChildRemoval}
+ */
+ void collectReparentChange(@NonNull WindowContainer wc, @NonNull WindowContainer newParent) {
+ if (!mChanges.containsKey(wc)) {
+ // #collectReparentChange() will be called when the window is reparented. Skip if it is
+ // a window that has not been collected, which means we don't care about this window for
+ // the current transition.
+ return;
+ }
+ final ChangeInfo change = mChanges.get(wc);
+ // Use the current common ancestor if there are multiple reparent, and the original parent
+ // has been detached. Otherwise, use the original parent before the transition.
+ final WindowContainer prevParent =
+ change.mStartParent == null || change.mStartParent.isAttached()
+ ? change.mStartParent
+ : change.mCommonAncestor;
+ if (prevParent == null || !prevParent.isAttached()) {
+ Slog.w(TAG, "Trying to collect reparenting of a window after the previous parent has"
+ + " been detached: " + wc);
+ return;
+ }
+ if (prevParent == newParent) {
+ Slog.w(TAG, "Trying to collect reparenting of a window that has not been reparented: "
+ + wc);
+ return;
+ }
+ if (!newParent.isAttached()) {
+ Slog.w(TAG, "Trying to collect reparenting of a window that is not attached after"
+ + " reparenting: " + wc);
+ return;
+ }
+ WindowContainer ancestor = newParent;
+ while (prevParent != ancestor && !prevParent.isDescendantOf(ancestor)) {
+ ancestor = ancestor.getParent();
+ }
+ change.mCommonAncestor = ancestor;
+ }
+
+ /**
* @return {@code true} if `wc` is a participant or is a descendant of one.
*/
boolean isInTransition(WindowContainer wc) {
@@ -830,8 +872,8 @@
void abort() {
// This calls back into itself via controller.abort, so just early return here.
if (mState == STATE_ABORT) return;
- if (mState != STATE_COLLECTING) {
- throw new IllegalStateException("Too late to abort.");
+ if (mState != STATE_COLLECTING && mState != STATE_STARTED) {
+ throw new IllegalStateException("Too late to abort. state=" + mState);
}
ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, "Aborting Transition: %d", mSyncId);
mState = STATE_ABORT;
@@ -1524,20 +1566,7 @@
return out;
}
- // Find the top-most shared ancestor of app targets.
- WindowContainer<?> ancestor = topApp.getParent();
- // Go up ancestor parent chain until all targets are descendants.
- ancestorLoop:
- while (ancestor != null) {
- for (int i = sortedTargets.size() - 1; i >= 0; --i) {
- final WindowContainer wc = sortedTargets.get(i);
- if (!isWallpaper(wc) && !wc.isDescendantOf(ancestor)) {
- ancestor = ancestor.getParent();
- continue ancestorLoop;
- }
- }
- break;
- }
+ WindowContainer<?> ancestor = findCommonAncestor(sortedTargets, changes, topApp);
// make leash based on highest (z-order) direct child of ancestor with a participant.
WindowContainer leashReference = sortedTargets.get(0);
@@ -1654,6 +1683,46 @@
return out;
}
+ /**
+ * Finds the top-most common ancestor of app targets.
+ *
+ * Makes sure that the previous parent is also a descendant to make sure the animation won't
+ * be covered by other windows below the previous parent. For example, when reparenting an
+ * activity from PiP Task to split screen Task.
+ */
+ @NonNull
+ private static WindowContainer<?> findCommonAncestor(
+ @NonNull ArrayList<WindowContainer> targets,
+ @NonNull ArrayMap<WindowContainer, ChangeInfo> changes,
+ @NonNull WindowContainer<?> topApp) {
+ WindowContainer<?> ancestor = topApp.getParent();
+ // Go up ancestor parent chain until all targets are descendants. Ancestor should never be
+ // null because all targets are attached.
+ for (int i = targets.size() - 1; i >= 0; i--) {
+ final WindowContainer wc = targets.get(i);
+ if (isWallpaper(wc)) {
+ // Skip the non-app window.
+ continue;
+ }
+ while (!wc.isDescendantOf(ancestor)) {
+ ancestor = ancestor.getParent();
+ }
+
+ // Make sure the previous parent is also a descendant to make sure the animation won't
+ // be covered by other windows below the previous parent. For example, when reparenting
+ // an activity from PiP Task to split screen Task.
+ final ChangeInfo change = changes.get(wc);
+ final WindowContainer prevParent = change.mCommonAncestor;
+ if (prevParent == null || !prevParent.isAttached()) {
+ continue;
+ }
+ while (prevParent != ancestor && !prevParent.isDescendantOf(ancestor)) {
+ ancestor = ancestor.getParent();
+ }
+ }
+ return ancestor;
+ }
+
private static WindowManager.LayoutParams getLayoutParamsForAnimationsStyle(int type,
ArrayList<WindowContainer> sortedTargets) {
// Find the layout params of the top-most application window that is part of the
@@ -1772,10 +1841,19 @@
@Retention(RetentionPolicy.SOURCE)
@interface Flag {}
- // Usually "post" change state.
+ /**
+ * "Parent" that is also included in the transition. When populating the parent changes, we
+ * may skip the intermediate parents, so this may not be the actual parent in the hierarchy.
+ */
WindowContainer mEndParent;
- // Parent before change state.
+ /** Actual parent window before change state. */
WindowContainer mStartParent;
+ /**
+ * When the window is reparented during the transition, this is the common ancestor window
+ * of the {@link #mStartParent} and the current parent. This is needed because the
+ * {@link #mStartParent} may have been detached when the transition starts.
+ */
+ WindowContainer mCommonAncestor;
// State tracking
boolean mExistenceChanged = false;
diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java
index ac85c9a..37bef3a 100644
--- a/services/core/java/com/android/server/wm/TransitionController.java
+++ b/services/core/java/com/android/server/wm/TransitionController.java
@@ -533,6 +533,17 @@
mCollectingTransition.collectVisibleChange(wc);
}
+ /**
+ * Records that a particular container has been reparented. This only effects windows that have
+ * already been collected in the transition. This should be called before reparenting because
+ * the old parent may be removed during reparenting, for example:
+ * {@link Task#shouldRemoveSelfOnLastChildRemoval}
+ */
+ void collectReparentChange(@NonNull WindowContainer wc, @NonNull WindowContainer newParent) {
+ if (!isCollecting()) return;
+ mCollectingTransition.collectReparentChange(wc, newParent);
+ }
+
/** @see Transition#mStatusBarTransitionDelay */
void setStatusBarTransitionDelay(long delay) {
if (mCollectingTransition == null) return;
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 0b5de85..73d4496 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -542,6 +542,10 @@
throw new IllegalArgumentException("WC=" + this + " already child of " + mParent);
}
+ // Collect before removing child from old parent, because the old parent may be removed if
+ // this is the last child in it.
+ mTransitionController.collectReparentChange(this, newParent);
+
// The display object before reparenting as that might lead to old parent getting removed
// from the display if it no longer has any child.
final DisplayContent prevDc = oldParent.getDisplayContent();
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 6d750a4..f30c435 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -29,7 +29,6 @@
import static android.os.PowerManager.DRAW_WAKE_LOCK;
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
import static android.view.InsetsState.ITYPE_IME;
-import static android.view.InsetsState.ITYPE_INVALID;
import static android.view.SurfaceControl.Transaction;
import static android.view.SurfaceControl.getGlobalTransaction;
import static android.view.ViewRootImpl.LOCAL_LAYOUT;
@@ -1673,14 +1672,11 @@
if (rotatedState != null) {
return insetsPolicy.adjustInsetsForWindow(this, rotatedState);
}
- final InsetsSourceProvider provider = getControllableInsetProvider();
- final @InternalInsetsType int insetTypeProvidedByWindow = provider != null
- ? provider.getSource().getType() : ITYPE_INVALID;
final InsetsState rawInsetsState =
mFrozenInsetsState != null ? mFrozenInsetsState : getMergedInsetsState();
final InsetsState insetsStateForWindow = insetsPolicy
- .enforceInsetsPolicyForTarget(insetTypeProvidedByWindow,
- getWindowingMode(), isAlwaysOnTop(), mAttrs.type, rawInsetsState);
+ .enforceInsetsPolicyForTarget(
+ getWindowingMode(), isAlwaysOnTop(), mAttrs, rawInsetsState);
return insetsPolicy.adjustInsetsForWindow(this, insetsStateForWindow,
includeTransient);
}
@@ -5713,6 +5709,15 @@
return super.getAnimationLeashParent();
}
+ @Override
+ public void onAnimationLeashCreated(Transaction t, SurfaceControl leash) {
+ super.onAnimationLeashCreated(t, leash);
+ if (isStartingWindowAssociatedToTask()) {
+ // Make sure the animation leash is still on top of the task.
+ t.setLayer(leash, Integer.MAX_VALUE);
+ }
+ }
+
// TODO(b/70040778): We should aim to eliminate the last user of TYPE_APPLICATION_MEDIA
// then we can drop all negative layering on the windowing side and simply inherit
// the default implementation here.
diff --git a/services/credentials/java/com/android/server/credentials/CredentialManagerUi.java b/services/credentials/java/com/android/server/credentials/CredentialManagerUi.java
index 69fb1ea..dcf094f 100644
--- a/services/credentials/java/com/android/server/credentials/CredentialManagerUi.java
+++ b/services/credentials/java/com/android/server/credentials/CredentialManagerUi.java
@@ -16,7 +16,6 @@
package com.android.server.credentials;
import android.annotation.NonNull;
-import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.credentials.ui.IntentFactory;
@@ -48,7 +47,7 @@
};
private void handleUiResult(int resultCode, Bundle resultData) {
- if (resultCode == Activity.RESULT_OK) {
+ if (resultCode == UserSelectionDialogResult.RESULT_CODE_DIALOG_COMPLETE_WITH_SELECTION) {
UserSelectionDialogResult selection = UserSelectionDialogResult
.fromResultData(resultData);
if (selection != null) {
@@ -56,7 +55,7 @@
} else {
Slog.i(TAG, "No selection found in UI result");
}
- } else if (resultCode == Activity.RESULT_CANCELED) {
+ } else if (resultCode == UserSelectionDialogResult.RESULT_CODE_DIALOG_CANCELED) {
mCallbacks.onUiCancelation();
}
}
@@ -84,8 +83,9 @@
*/
public void show(RequestInfo requestInfo, ArrayList<ProviderData> providerDataList) {
Log.i(TAG, "In show");
- Intent intent = IntentFactory.newIntent(requestInfo, providerDataList,
- mResultReceiver);
+ Intent intent = IntentFactory.newIntent(
+ requestInfo, providerDataList,
+ new ArrayList<>(), mResultReceiver);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mContext.startActivity(intent);
}
diff --git a/services/credentials/java/com/android/server/credentials/ProviderGetSession.java b/services/credentials/java/com/android/server/credentials/ProviderGetSession.java
index 24610df..ff2107a 100644
--- a/services/credentials/java/com/android/server/credentials/ProviderGetSession.java
+++ b/services/credentials/java/com/android/server/credentials/ProviderGetSession.java
@@ -20,7 +20,7 @@
import android.annotation.Nullable;
import android.app.slice.Slice;
import android.credentials.ui.Entry;
-import android.credentials.ui.ProviderData;
+import android.credentials.ui.GetCredentialProviderData;
import android.service.credentials.Action;
import android.service.credentials.CredentialEntry;
import android.service.credentials.CredentialProviderInfo;
@@ -117,7 +117,7 @@
}
@Override
- protected final ProviderData prepareUiData() throws IllegalArgumentException {
+ protected GetCredentialProviderData prepareUiData() throws IllegalArgumentException {
Log.i(TAG, "In prepareUiData");
if (!ProviderSession.isCompletionStatus(getStatus())) {
Log.i(TAG, "In prepareUiData not complete");
@@ -147,7 +147,7 @@
* To be called by {@link ProviderGetSession} when the UI is to be invoked.
*/
@Nullable
- private ProviderData prepareUiProviderDataWithCredentials(@NonNull
+ private GetCredentialProviderData prepareUiProviderDataWithCredentials(@NonNull
CredentialsDisplayContent content) {
Log.i(TAG, "in prepareUiProviderData");
List<Entry> credentialEntries = new ArrayList<>();
@@ -173,15 +173,10 @@
action.getSlice()));
}
- // TODO : Set the correct last used time
- return new ProviderData.Builder(mComponentName.flattenToString(),
- mProviderInfo.getServiceLabel() == null ? "" :
- mProviderInfo.getServiceLabel().toString(),
- /*icon=*/null)
+ return new GetCredentialProviderData.Builder(mComponentName.flattenToString())
.setCredentialEntries(credentialEntries)
.setActionChips(actionChips)
.setAuthenticationEntry(authenticationEntry)
- .setLastUsedTimeMillis(0)
.build();
}
@@ -189,7 +184,7 @@
* To be called by {@link ProviderGetSession} when the UI is to be invoked.
*/
@Nullable
- private ProviderData prepareUiProviderDataWithAuthentication(@NonNull
+ private GetCredentialProviderData prepareUiProviderDataWithAuthentication(@NonNull
Action authenticationEntry) {
// TODO : Implement authentication flow
return null;
diff --git a/services/tests/InputMethodSystemServerTests/Android.bp b/services/tests/InputMethodSystemServerTests/Android.bp
new file mode 100644
index 0000000..939fb6a
--- /dev/null
+++ b/services/tests/InputMethodSystemServerTests/Android.bp
@@ -0,0 +1,62 @@
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+android_test {
+ name: "FrameworksInputMethodSystemServerTests",
+ defaults: [
+ "modules-utils-testable-device-config-defaults",
+ ],
+
+ srcs: [
+ "src/**/*.java",
+ ],
+
+ static_libs: [
+ "androidx.test.core",
+ "androidx.test.runner",
+ "androidx.test.espresso.core",
+ "androidx.test.espresso.contrib",
+ "androidx.test.ext.truth",
+ "frameworks-base-testutils",
+ "mockito-target-extended-minus-junit4",
+ "platform-test-annotations",
+ "services.core",
+ "servicestests-core-utils",
+ "servicestests-utils-mockito-extended",
+ "truth-prebuilt",
+ ],
+
+ libs: [
+ "android.test.mock",
+ "android.test.base",
+ "android.test.runner",
+ ],
+
+ certificate: "platform",
+ platform_apis: true,
+ test_suites: ["device-tests"],
+
+ optimize: {
+ enabled: false,
+ },
+}
diff --git a/services/tests/InputMethodSystemServerTests/AndroidManifest.xml b/services/tests/InputMethodSystemServerTests/AndroidManifest.xml
new file mode 100644
index 0000000..12e7cfc
--- /dev/null
+++ b/services/tests/InputMethodSystemServerTests/AndroidManifest.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.frameworks.inputmethodtests">
+
+ <uses-sdk android:targetSdkVersion="31" />
+
+ <!-- Permissions required for granting and logging -->
+ <uses-permission android:name="android.permission.LOG_COMPAT_CHANGE"/>
+ <uses-permission android:name="android.permission.READ_COMPAT_CHANGE_CONFIG"/>
+ <uses-permission android:name="android.permission.OVERRIDE_COMPAT_CHANGE_CONFIG"/>
+ <uses-permission android:name="android.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD"/>
+
+ <!-- Permissions for reading system info -->
+ <uses-permission android:name="android.permission.READ_DEVICE_CONFIG" />
+ <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
+
+ <application android:testOnly="true"
+ android:debuggable="true">
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation
+ android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.frameworks.inputmethodtests"
+ android:label="Frameworks InputMethod System Service Tests" />
+
+</manifest>
diff --git a/services/tests/InputMethodSystemServerTests/AndroidTest.xml b/services/tests/InputMethodSystemServerTests/AndroidTest.xml
new file mode 100644
index 0000000..92be780
--- /dev/null
+++ b/services/tests/InputMethodSystemServerTests/AndroidTest.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Runs Frameworks InputMethod System Services Tests.">
+ <option name="test-suite-tag" value="apct" />
+ <option name="test-suite-tag" value="apct-instrumentation" />
+
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="install-arg" value="-t" />
+ <option name="test-file-name" value="FrameworksInputMethodSystemServerTests.apk" />
+ </target_preparer>
+
+ <option name="test-tag" value="FrameworksInputMethodSystemServerTests" />
+
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="com.android.frameworks.inputmethodtests" />
+ <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
+ <option name="hidden-api-checks" value="false"/>
+ </test>
+
+ <!-- Collect the files in the dump directory for debugging -->
+ <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
+ <option name="directory-keys" value="/sdcard/FrameworksInputMethodSystemServerTests/" />
+ <option name="collect-on-run-ended-only" value="true" />
+ </metrics_collector>
+</configuration>
diff --git a/services/tests/InputMethodSystemServerTests/OWNERS b/services/tests/InputMethodSystemServerTests/OWNERS
new file mode 100644
index 0000000..1f2c036
--- /dev/null
+++ b/services/tests/InputMethodSystemServerTests/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/inputmethod/OWNERS
diff --git a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodManagerServiceTestBase.java b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodManagerServiceTestBase.java
new file mode 100644
index 0000000..3fbc400
--- /dev/null
+++ b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodManagerServiceTestBase.java
@@ -0,0 +1,259 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.inputmethod;
+
+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.mockitoSession;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+
+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.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.ActivityManagerInternal;
+import android.content.Context;
+import android.content.pm.PackageManagerInternal;
+import android.hardware.display.DisplayManagerInternal;
+import android.hardware.input.IInputManager;
+import android.hardware.input.InputManager;
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.UserHandle;
+import android.view.inputmethod.EditorInfo;
+import android.window.ImeOnBackInvokedDispatcher;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.internal.compat.IPlatformCompat;
+import com.android.internal.inputmethod.IInputMethod;
+import com.android.internal.inputmethod.IInputMethodClient;
+import com.android.internal.inputmethod.IRemoteAccessibilityInputConnection;
+import com.android.internal.inputmethod.IRemoteInputConnection;
+import com.android.internal.inputmethod.InputBindResult;
+import com.android.internal.view.IInputMethodManager;
+import com.android.server.LocalServices;
+import com.android.server.ServiceThread;
+import com.android.server.SystemServerInitThreadPool;
+import com.android.server.SystemService;
+import com.android.server.input.InputManagerInternal;
+import com.android.server.pm.UserManagerInternal;
+import com.android.server.wm.WindowManagerInternal;
+
+import org.junit.After;
+import org.junit.Before;
+import org.mockito.Mock;
+import org.mockito.MockitoSession;
+import org.mockito.quality.Strictness;
+
+/** Base class for testing {@link InputMethodManagerService}. */
+public class InputMethodManagerServiceTestBase {
+ protected static final String TEST_SELECTED_IME_ID = "test.ime";
+ protected static final String TEST_EDITOR_PKG_NAME = "test.editor";
+ protected static final String TEST_FOCUSED_WINDOW_NAME = "test.editor/activity";
+ protected static final WindowManagerInternal.ImeTargetInfo TEST_IME_TARGET_INFO =
+ new WindowManagerInternal.ImeTargetInfo(
+ TEST_FOCUSED_WINDOW_NAME,
+ TEST_FOCUSED_WINDOW_NAME,
+ TEST_FOCUSED_WINDOW_NAME,
+ TEST_FOCUSED_WINDOW_NAME,
+ TEST_FOCUSED_WINDOW_NAME);
+ protected static final InputBindResult SUCCESS_WAITING_IME_BINDING_RESULT =
+ new InputBindResult(
+ InputBindResult.ResultCode.SUCCESS_WAITING_IME_BINDING,
+ null,
+ null,
+ null,
+ "0",
+ 0,
+ null,
+ false);
+
+ @Mock protected WindowManagerInternal mMockWindowManagerInternal;
+ @Mock protected ActivityManagerInternal mMockActivityManagerInternal;
+ @Mock protected PackageManagerInternal mMockPackageManagerInternal;
+ @Mock protected InputManagerInternal mMockInputManagerInternal;
+ @Mock protected DisplayManagerInternal mMockDisplayManagerInternal;
+ @Mock protected UserManagerInternal mMockUserManagerInternal;
+ @Mock protected InputMethodBindingController mMockInputMethodBindingController;
+ @Mock protected IInputMethodClient mMockInputMethodClient;
+ @Mock protected IBinder mWindowToken;
+ @Mock protected IRemoteInputConnection mMockRemoteInputConnection;
+ @Mock protected IRemoteAccessibilityInputConnection mMockRemoteAccessibilityInputConnection;
+ @Mock protected ImeOnBackInvokedDispatcher mMockImeOnBackInvokedDispatcher;
+ @Mock protected IInputMethodManager.Stub mMockIInputMethodManager;
+ @Mock protected IPlatformCompat.Stub mMockIPlatformCompat;
+ @Mock protected IInputMethod mMockInputMethod;
+ @Mock protected IBinder mMockInputMethodBinder;
+ @Mock protected IInputManager mMockIInputManager;
+
+ protected Context mContext;
+ protected MockitoSession mMockingSession;
+ protected int mTargetSdkVersion;
+ protected int mCallingUserId;
+ protected EditorInfo mEditorInfo;
+ protected IInputMethodInvoker mMockInputMethodInvoker;
+ protected InputMethodManagerService mInputMethodManagerService;
+ protected ServiceThread mServiceThread;
+
+ @Before
+ public void setUp() throws RemoteException {
+ mMockingSession =
+ mockitoSession()
+ .initMocks(this)
+ .strictness(Strictness.LENIENT)
+ .mockStatic(LocalServices.class)
+ .mockStatic(ServiceManager.class)
+ .mockStatic(SystemServerInitThreadPool.class)
+ .startMocking();
+
+ mContext = InstrumentationRegistry.getInstrumentation().getContext();
+ spyOn(mContext);
+
+ mTargetSdkVersion = mContext.getApplicationInfo().targetSdkVersion;
+ mCallingUserId = UserHandle.getCallingUserId();
+ mEditorInfo = new EditorInfo();
+ mEditorInfo.packageName = TEST_EDITOR_PKG_NAME;
+
+ // Injecting and mocking local services.
+ doReturn(mMockWindowManagerInternal)
+ .when(() -> LocalServices.getService(WindowManagerInternal.class));
+ doReturn(mMockActivityManagerInternal)
+ .when(() -> LocalServices.getService(ActivityManagerInternal.class));
+ doReturn(mMockPackageManagerInternal)
+ .when(() -> LocalServices.getService(PackageManagerInternal.class));
+ doReturn(mMockInputManagerInternal)
+ .when(() -> LocalServices.getService(InputManagerInternal.class));
+ doReturn(mMockDisplayManagerInternal)
+ .when(() -> LocalServices.getService(DisplayManagerInternal.class));
+ doReturn(mMockUserManagerInternal)
+ .when(() -> LocalServices.getService(UserManagerInternal.class));
+ doReturn(mMockIInputMethodManager)
+ .when(() -> ServiceManager.getServiceOrThrow(Context.INPUT_METHOD_SERVICE));
+ doReturn(mMockIPlatformCompat)
+ .when(() -> ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE));
+
+ // Stubbing out context related methods to avoid the system holding strong references to
+ // InputMethodManagerService.
+ doNothing().when(mContext).enforceCallingPermission(anyString(), anyString());
+ doNothing().when(mContext).sendBroadcastAsUser(any(), any());
+ doReturn(null).when(mContext).registerReceiver(any(), any());
+ doReturn(null)
+ .when(mContext)
+ .registerReceiverAsUser(any(), any(), any(), anyString(), any(), anyInt());
+
+ // Injecting and mocked InputMethodBindingController and InputMethod.
+ mMockInputMethodInvoker = IInputMethodInvoker.create(mMockInputMethod);
+ InputManager.resetInstance(mMockIInputManager);
+ synchronized (ImfLock.class) {
+ when(mMockInputMethodBindingController.getCurMethod())
+ .thenReturn(mMockInputMethodInvoker);
+ when(mMockInputMethodBindingController.bindCurrentMethod())
+ .thenReturn(SUCCESS_WAITING_IME_BINDING_RESULT);
+ doNothing().when(mMockInputMethodBindingController).unbindCurrentMethod();
+ when(mMockInputMethodBindingController.getSelectedMethodId())
+ .thenReturn(TEST_SELECTED_IME_ID);
+ }
+
+ // Shuffling around all other initialization to make the test runnable.
+ when(mMockIInputManager.getInputDeviceIds()).thenReturn(new int[0]);
+ when(mMockIInputMethodManager.isImeTraceEnabled()).thenReturn(false);
+ when(mMockIPlatformCompat.isChangeEnabledByUid(anyLong(), anyInt())).thenReturn(true);
+ when(mMockUserManagerInternal.isUserRunning(anyInt())).thenReturn(true);
+ when(mMockUserManagerInternal.getProfileIds(anyInt(), anyBoolean()))
+ .thenReturn(new int[] {0});
+ when(mMockActivityManagerInternal.isSystemReady()).thenReturn(true);
+ when(mMockPackageManagerInternal.getPackageUid(anyString(), anyLong(), anyInt()))
+ .thenReturn(Binder.getCallingUid());
+ when(mMockWindowManagerInternal.onToggleImeRequested(anyBoolean(), any(), any(), anyInt()))
+ .thenReturn(TEST_IME_TARGET_INFO);
+ when(mMockInputMethodClient.asBinder()).thenReturn(mMockInputMethodBinder);
+
+ // Used by lazy initializing draw IMS nav bar at InputMethodManagerService#systemRunning(),
+ // which is ok to be mocked out for now.
+ doReturn(null).when(() -> SystemServerInitThreadPool.submit(any(), anyString()));
+
+ mServiceThread =
+ new ServiceThread(
+ "TestServiceThread",
+ Process.THREAD_PRIORITY_FOREGROUND, /* allowIo */
+ false);
+ mInputMethodManagerService =
+ new InputMethodManagerService(
+ mContext, mServiceThread, mMockInputMethodBindingController);
+
+ // Start a InputMethodManagerService.Lifecycle to publish and manage the lifecycle of
+ // InputMethodManagerService, which is closer to the real situation.
+ InputMethodManagerService.Lifecycle lifecycle =
+ new InputMethodManagerService.Lifecycle(mContext, mInputMethodManagerService);
+
+ // Public local InputMethodManagerService.
+ lifecycle.onStart();
+ try {
+ // After this boot phase, services can broadcast Intents.
+ lifecycle.onBootPhase(SystemService.PHASE_ACTIVITY_MANAGER_READY);
+ } catch (SecurityException e) {
+ // Security exception to permission denial is expected in test, mocking out to ensure
+ // InputMethodManagerService as system ready state.
+ if (!e.getMessage().contains("Permission Denial: not allowed to send broadcast")) {
+ throw e;
+ }
+ }
+
+ // Call InputMethodManagerService#addClient() as a preparation to start interacting with it.
+ mInputMethodManagerService.addClient(mMockInputMethodClient, mMockRemoteInputConnection, 0);
+ }
+
+ @After
+ public void tearDown() {
+ if (mServiceThread != null) {
+ mServiceThread.quitSafely();
+ }
+
+ if (mMockingSession != null) {
+ mMockingSession.finishMocking();
+ }
+ }
+
+ protected void verifyShowSoftInput(boolean setVisible, boolean showSoftInput)
+ throws RemoteException {
+ synchronized (ImfLock.class) {
+ verify(mMockInputMethodBindingController, times(setVisible ? 1 : 0))
+ .setCurrentMethodVisible();
+ }
+ verify(mMockInputMethod, times(showSoftInput ? 1 : 0))
+ .showSoftInput(any(), anyInt(), any());
+ }
+
+ protected void verifyHideSoftInput(boolean setNotVisible, boolean hideSoftInput)
+ throws RemoteException {
+ synchronized (ImfLock.class) {
+ verify(mMockInputMethodBindingController, times(setNotVisible ? 1 : 0))
+ .setCurrentMethodNotVisible();
+ }
+ verify(mMockInputMethod, times(hideSoftInput ? 1 : 0))
+ .hideSoftInput(any(), anyInt(), any());
+ }
+}
diff --git a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodManagerServiceWindowGainedFocusTest.java b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodManagerServiceWindowGainedFocusTest.java
new file mode 100644
index 0000000..ffa2729
--- /dev/null
+++ b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodManagerServiceWindowGainedFocusTest.java
@@ -0,0 +1,266 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.inputmethod;
+
+import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
+import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN;
+import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
+import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED;
+import static android.view.WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;
+import static android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN;
+import static android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE;
+import static android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN;
+import static android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED;
+import static android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED;
+import static android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.when;
+
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
+import android.view.inputmethod.EditorInfo;
+import android.window.ImeOnBackInvokedDispatcher;
+
+import com.android.internal.inputmethod.IInputMethodClient;
+import com.android.internal.inputmethod.IRemoteAccessibilityInputConnection;
+import com.android.internal.inputmethod.IRemoteInputConnection;
+import com.android.internal.inputmethod.InputBindResult;
+import com.android.internal.inputmethod.InputMethodDebug;
+import com.android.internal.inputmethod.StartInputFlags;
+import com.android.internal.inputmethod.StartInputReason;
+import com.android.server.wm.WindowManagerInternal;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Test the behavior of {@link InputMethodManagerService#startInputOrWindowGainedFocus(int,
+ * IInputMethodClient, IBinder, int, int, int, EditorInfo, IRemoteInputConnection,
+ * IRemoteAccessibilityInputConnection, int, int, ImeOnBackInvokedDispatcher)}.
+ */
+@RunWith(Parameterized.class)
+public class InputMethodManagerServiceWindowGainedFocusTest
+ extends InputMethodManagerServiceTestBase {
+ private static final String TAG = "IMMSWindowGainedFocusTest";
+
+ private static final int[] SOFT_INPUT_STATE_FLAGS =
+ new int[] {
+ SOFT_INPUT_STATE_UNSPECIFIED,
+ SOFT_INPUT_STATE_UNCHANGED,
+ SOFT_INPUT_STATE_HIDDEN,
+ SOFT_INPUT_STATE_ALWAYS_HIDDEN,
+ SOFT_INPUT_STATE_VISIBLE,
+ SOFT_INPUT_STATE_ALWAYS_VISIBLE
+ };
+ private static final int[] SOFT_INPUT_ADJUST_FLAGS =
+ new int[] {
+ SOFT_INPUT_ADJUST_UNSPECIFIED,
+ SOFT_INPUT_ADJUST_RESIZE,
+ SOFT_INPUT_ADJUST_PAN,
+ SOFT_INPUT_ADJUST_NOTHING
+ };
+ private static final int DEFAULT_SOFT_INPUT_FLAG =
+ StartInputFlags.VIEW_HAS_FOCUS | StartInputFlags.IS_TEXT_EDITOR;
+
+ @Parameterized.Parameters(name = "softInputState={0}, softInputAdjustment={1}")
+ public static List<Object[]> softInputModeConfigs() {
+ ArrayList<Object[]> params = new ArrayList<>();
+ for (int softInputState : SOFT_INPUT_STATE_FLAGS) {
+ for (int softInputAdjust : SOFT_INPUT_ADJUST_FLAGS) {
+ params.add(new Object[] {softInputState, softInputAdjust});
+ }
+ }
+ return params;
+ }
+
+ private final int mSoftInputState;
+ private final int mSoftInputAdjustment;
+
+ public InputMethodManagerServiceWindowGainedFocusTest(
+ int softInputState, int softInputAdjustment) {
+ mSoftInputState = softInputState;
+ mSoftInputAdjustment = softInputAdjustment;
+ }
+
+ @Test
+ public void startInputOrWindowGainedFocus_forwardNavigation() throws RemoteException {
+ mockHasImeFocusAndRestoreImeVisibility(false /* restoreImeVisibility */);
+
+ assertThat(
+ startInputOrWindowGainedFocus(
+ DEFAULT_SOFT_INPUT_FLAG, true /* forwardNavigation */))
+ .isEqualTo(SUCCESS_WAITING_IME_BINDING_RESULT);
+
+ switch (mSoftInputState) {
+ case SOFT_INPUT_STATE_UNSPECIFIED:
+ boolean showSoftInput = mSoftInputAdjustment == SOFT_INPUT_ADJUST_RESIZE;
+ verifyShowSoftInput(
+ showSoftInput /* setVisible */, showSoftInput /* showSoftInput */);
+ // Soft input was hidden by default, so it doesn't need to call
+ // {@code IMS#hideSoftInput()}.
+ verifyHideSoftInput(!showSoftInput /* setNotVisible */, false /* hideSoftInput */);
+ break;
+ case SOFT_INPUT_STATE_VISIBLE:
+ case SOFT_INPUT_STATE_ALWAYS_VISIBLE:
+ verifyShowSoftInput(true /* setVisible */, true /* showSoftInput */);
+ verifyHideSoftInput(false /* setNotVisible */, false /* hideSoftInput */);
+ break;
+ case SOFT_INPUT_STATE_UNCHANGED: // Do nothing
+ verifyShowSoftInput(false /* setVisible */, false /* showSoftInput */);
+ verifyHideSoftInput(false /* setNotVisible */, false /* hideSoftInput */);
+ break;
+ case SOFT_INPUT_STATE_HIDDEN:
+ case SOFT_INPUT_STATE_ALWAYS_HIDDEN:
+ verifyShowSoftInput(false /* setVisible */, false /* showSoftInput */);
+ // Soft input was hidden by default, so it doesn't need to call
+ // {@code IMS#hideSoftInput()}.
+ verifyHideSoftInput(true /* setNotVisible */, false /* hideSoftInput */);
+ break;
+ default:
+ throw new IllegalStateException(
+ "Unhandled soft input mode: "
+ + InputMethodDebug.softInputModeToString(mSoftInputState));
+ }
+ }
+
+ @Test
+ public void startInputOrWindowGainedFocus_notForwardNavigation() throws RemoteException {
+ mockHasImeFocusAndRestoreImeVisibility(false /* restoreImeVisibility */);
+
+ assertThat(
+ startInputOrWindowGainedFocus(
+ DEFAULT_SOFT_INPUT_FLAG, false /* forwardNavigation */))
+ .isEqualTo(SUCCESS_WAITING_IME_BINDING_RESULT);
+
+ switch (mSoftInputState) {
+ case SOFT_INPUT_STATE_UNSPECIFIED:
+ boolean hideSoftInput = mSoftInputAdjustment != SOFT_INPUT_ADJUST_RESIZE;
+ verifyShowSoftInput(false /* setVisible */, false /* showSoftInput */);
+ // Soft input was hidden by default, so it doesn't need to call
+ // {@code IMS#hideSoftInput()}.
+ verifyHideSoftInput(hideSoftInput /* setNotVisible */, false /* hideSoftInput */);
+ break;
+ case SOFT_INPUT_STATE_VISIBLE:
+ case SOFT_INPUT_STATE_HIDDEN:
+ case SOFT_INPUT_STATE_UNCHANGED: // Do nothing
+ verifyShowSoftInput(false /* setVisible */, false /* showSoftInput */);
+ verifyHideSoftInput(false /* setNotVisible */, false /* hideSoftInput */);
+ break;
+ case SOFT_INPUT_STATE_ALWAYS_VISIBLE:
+ verifyShowSoftInput(true /* setVisible */, true /* showSoftInput */);
+ verifyHideSoftInput(false /* setNotVisible */, false /* hideSoftInput */);
+ break;
+ case SOFT_INPUT_STATE_ALWAYS_HIDDEN:
+ verifyShowSoftInput(false /* setVisible */, false /* showSoftInput */);
+ // Soft input was hidden by default, so it doesn't need to call
+ // {@code IMS#hideSoftInput()}.
+ verifyHideSoftInput(true /* setNotVisible */, false /* hideSoftInput */);
+ break;
+ default:
+ throw new IllegalStateException(
+ "Unhandled soft input mode: "
+ + InputMethodDebug.softInputModeToString(mSoftInputState));
+ }
+ }
+
+ @Test
+ public void startInputOrWindowGainedFocus_userNotRunning() throws RemoteException {
+ when(mMockUserManagerInternal.isUserRunning(anyInt())).thenReturn(false);
+
+ assertThat(
+ startInputOrWindowGainedFocus(
+ DEFAULT_SOFT_INPUT_FLAG, true /* forwardNavigation */))
+ .isEqualTo(InputBindResult.INVALID_USER);
+ verifyShowSoftInput(false /* setVisible */, false /* showSoftInput */);
+ verifyHideSoftInput(false /* setNotVisible */, false /* hideSoftInput */);
+ }
+
+ @Test
+ public void startInputOrWindowGainedFocus_invalidFocusStatus() throws RemoteException {
+ int[] invalidImeClientFocus =
+ new int[] {
+ WindowManagerInternal.ImeClientFocusResult.NOT_IME_TARGET_WINDOW,
+ WindowManagerInternal.ImeClientFocusResult.DISPLAY_ID_MISMATCH,
+ WindowManagerInternal.ImeClientFocusResult.INVALID_DISPLAY_ID
+ };
+ InputBindResult[] inputBingResult =
+ new InputBindResult[] {
+ InputBindResult.NOT_IME_TARGET_WINDOW,
+ InputBindResult.DISPLAY_ID_MISMATCH,
+ InputBindResult.INVALID_DISPLAY_ID
+ };
+
+ for (int i = 0; i < invalidImeClientFocus.length; i++) {
+ when(mMockWindowManagerInternal.hasInputMethodClientFocus(
+ any(), anyInt(), anyInt(), anyInt()))
+ .thenReturn(invalidImeClientFocus[i]);
+
+ assertThat(
+ startInputOrWindowGainedFocus(
+ DEFAULT_SOFT_INPUT_FLAG, true /* forwardNavigation */))
+ .isEqualTo(inputBingResult[i]);
+ verifyShowSoftInput(false /* setVisible */, false /* showSoftInput */);
+ verifyHideSoftInput(false /* setNotVisible */, false /* hideSoftInput */);
+ }
+ }
+
+ private InputBindResult startInputOrWindowGainedFocus(
+ int startInputFlag, boolean forwardNavigation) {
+ int softInputMode = mSoftInputState | mSoftInputAdjustment;
+ if (forwardNavigation) {
+ softInputMode |= SOFT_INPUT_IS_FORWARD_NAVIGATION;
+ }
+
+ Log.i(
+ TAG,
+ "startInputOrWindowGainedFocus() softInputStateFlag="
+ + InputMethodDebug.softInputModeToString(mSoftInputState)
+ + ", softInputAdjustFlag="
+ + InputMethodDebug.softInputModeToString(mSoftInputAdjustment));
+
+ return mInputMethodManagerService.startInputOrWindowGainedFocus(
+ StartInputReason.WINDOW_FOCUS_GAIN /* startInputReason */,
+ mMockInputMethodClient /* client */,
+ mWindowToken /* windowToken */,
+ startInputFlag /* startInputFlags */,
+ softInputMode /* softInputMode */,
+ 0 /* windowFlags */,
+ mEditorInfo /* editorInfo */,
+ mMockRemoteInputConnection /* inputConnection */,
+ mMockRemoteAccessibilityInputConnection /* remoteAccessibilityInputConnection */,
+ mTargetSdkVersion /* unverifiedTargetSdkVersion */,
+ mCallingUserId /* userId */,
+ mMockImeOnBackInvokedDispatcher /* imeDispatcher */);
+ }
+
+ private void mockHasImeFocusAndRestoreImeVisibility(boolean restoreImeVisibility) {
+ when(mMockWindowManagerInternal.hasInputMethodClientFocus(
+ any(), anyInt(), anyInt(), anyInt()))
+ .thenReturn(WindowManagerInternal.ImeClientFocusResult.HAS_IME_FOCUS);
+ when(mMockWindowManagerInternal.shouldRestoreImeVisibility(any()))
+ .thenReturn(restoreImeVisibility);
+ }
+}
diff --git a/services/tests/mockingservicestests/Android.bp b/services/tests/mockingservicestests/Android.bp
index 16317fe..73b1907c 100644
--- a/services/tests/mockingservicestests/Android.bp
+++ b/services/tests/mockingservicestests/Android.bp
@@ -78,6 +78,12 @@
"servicestests-core-utils",
],
+ java_resources: [
+ ":apex.test",
+ ":test.rebootless_apex_v1",
+ ":test.rebootless_apex_v2",
+ ],
+
jni_libs: [
"libpsi",
],
diff --git a/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java
index cb14864..2583f44 100644
--- a/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java
@@ -325,7 +325,7 @@
doNothing().when(mAlarmManager).set(anyInt(), anyLong(), anyString(), any(), any());
doNothing().when(mAlarmManager).setExact(anyInt(), anyLong(), anyString(), any(), any());
doNothing().when(mAlarmManager)
- .setWindow(anyInt(), anyLong(), anyLong(), anyString(), any(), any());
+ .setWindow(anyInt(), anyLong(), anyLong(), anyString(), any(), any(Handler.class));
doReturn(mock(Sensor.class)).when(mSensorManager)
.getDefaultSensor(eq(Sensor.TYPE_SIGNIFICANT_MOTION), eq(true));
doReturn(true).when(mSensorManager).registerListener(any(), any(), anyInt());
@@ -1111,12 +1111,12 @@
alarmManagerInOrder.verify(mAlarmManager).setWindow(
eq(AlarmManager.ELAPSED_REALTIME),
eq(idleAfterInactiveExpiryTime),
- anyLong(), anyString(), any(), any());
+ anyLong(), anyString(), any(), any(Handler.class));
// Maintenance alarm
alarmManagerInOrder.verify(mAlarmManager).setWindow(
eq(AlarmManager.ELAPSED_REALTIME_WAKEUP),
eq(idleAfterInactiveExpiryTime + idlingTimeMs),
- anyLong(), anyString(), any(), any());
+ anyLong(), anyString(), any(), any(Handler.class));
final AlarmManager.OnAlarmListener progressionListener =
alarmListenerCaptor.getAllValues().get(0);
@@ -1130,7 +1130,7 @@
alarmManagerInOrder.verify(mAlarmManager).setWindow(
eq(AlarmManager.ELAPSED_REALTIME_WAKEUP),
eq(mInjector.nowElapsed + idlingTimeMs),
- anyLong(), anyString(), any(), any());
+ anyLong(), anyString(), any(), any(Handler.class));
for (int i = 0; i < 2; ++i) {
// IDLE->MAINTENANCE alarm
@@ -1144,12 +1144,12 @@
alarmManagerInOrder.verify(mAlarmManager).setWindow(
eq(AlarmManager.ELAPSED_REALTIME),
eq(maintenanceExpiryTime),
- anyLong(), anyString(), any(), any());
+ anyLong(), anyString(), any(), any(Handler.class));
// Set IDLE->MAINTENANCE
alarmManagerInOrder.verify(mAlarmManager).setWindow(
eq(AlarmManager.ELAPSED_REALTIME_WAKEUP),
eq(maintenanceExpiryTime + idlingTimeMs),
- anyLong(), anyString(), any(), any());
+ anyLong(), anyString(), any(), any(Handler.class));
// MAINTENANCE->IDLE alarm
mInjector.nowElapsed = mDeviceIdleController.getNextLightAlarmTimeForTesting();
@@ -1159,7 +1159,7 @@
alarmManagerInOrder.verify(mAlarmManager).setWindow(
eq(AlarmManager.ELAPSED_REALTIME_WAKEUP),
eq(mInjector.nowElapsed + idlingTimeMs),
- anyLong(), anyString(), any(), any());
+ anyLong(), anyString(), any(), any(Handler.class));
}
}
@@ -2019,7 +2019,8 @@
final ArgumentCaptor<AlarmManager.OnAlarmListener> alarmListener = ArgumentCaptor
.forClass(AlarmManager.OnAlarmListener.class);
doNothing().when(mAlarmManager).setWindow(
- anyInt(), anyLong(), anyLong(), eq("DeviceIdleController.motion"), any(), any());
+ anyInt(), anyLong(), anyLong(), eq("DeviceIdleController.motion"), any(),
+ any(Handler.class));
doNothing().when(mAlarmManager).setWindow(anyInt(), anyLong(), anyLong(),
eq("DeviceIdleController.motion_registration"),
alarmListener.capture(), any());
@@ -2063,7 +2064,8 @@
final ArgumentCaptor<AlarmManager.OnAlarmListener> alarmListener = ArgumentCaptor
.forClass(AlarmManager.OnAlarmListener.class);
doNothing().when(mAlarmManager).setWindow(
- anyInt(), anyLong(), anyLong(), eq("DeviceIdleController.motion"), any(), any());
+ anyInt(), anyLong(), anyLong(), eq("DeviceIdleController.motion"), any(),
+ any(Handler.class));
doNothing().when(mAlarmManager).setWindow(anyInt(), anyLong(), anyLong(),
eq("DeviceIdleController.motion_registration"),
alarmListener.capture(), any());
@@ -2130,7 +2132,7 @@
eq(SensorManager.SENSOR_DELAY_NORMAL));
inOrder.verify(mAlarmManager).setWindow(
anyInt(), eq(mInjector.nowElapsed + mConstants.MOTION_INACTIVE_TIMEOUT), anyLong(),
- eq("DeviceIdleController.motion"), any(), any());
+ eq("DeviceIdleController.motion"), any(), any(Handler.class));
final SensorEventListener listener = listenerCaptor.getValue();
// Trigger motion
@@ -2140,7 +2142,7 @@
final ArgumentCaptor<Long> registrationTimeCaptor = ArgumentCaptor.forClass(Long.class);
inOrder.verify(mAlarmManager).setWindow(
anyInt(), registrationTimeCaptor.capture(), anyLong(),
- eq("DeviceIdleController.motion_registration"), any(), any());
+ eq("DeviceIdleController.motion_registration"), any(), any(Handler.class));
// Make sure the listener is re-registered.
mInjector.nowElapsed = registrationTimeCaptor.getValue();
@@ -2150,7 +2152,7 @@
eq(SensorManager.SENSOR_DELAY_NORMAL));
final ArgumentCaptor<Long> timeoutCaptor = ArgumentCaptor.forClass(Long.class);
inOrder.verify(mAlarmManager).setWindow(anyInt(), timeoutCaptor.capture(), anyLong(),
- eq("DeviceIdleController.motion"), any(), any());
+ eq("DeviceIdleController.motion"), any(), any(Handler.class));
// No motion before timeout
stationaryListener.motionExpected = false;
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java
index e1a4c1d..de59603 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java
@@ -280,13 +280,13 @@
constants.TIMEOUT = 100;
constants.ALLOW_BG_ACTIVITY_START_TIMEOUT = 0;
final BroadcastSkipPolicy emptySkipPolicy = new BroadcastSkipPolicy(mAms) {
- public boolean shouldSkip(BroadcastRecord r, ResolveInfo info) {
+ public boolean shouldSkip(BroadcastRecord r, Object o) {
// Ignored
return false;
}
- public boolean shouldSkip(BroadcastRecord r, BroadcastFilter filter) {
+ public String shouldSkipMessage(BroadcastRecord r, Object o) {
// Ignored
- return false;
+ return null;
}
};
final BroadcastHistory emptyHistory = new BroadcastHistory(constants) {
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java
index 1753fc7..fc737d0 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java
@@ -41,6 +41,7 @@
import android.app.IActivityManager;
import android.app.UiModeManager;
import android.app.job.JobInfo;
+import android.app.job.JobParameters;
import android.app.job.JobScheduler;
import android.app.usage.UsageStatsManagerInternal;
import android.content.ComponentName;
@@ -235,6 +236,59 @@
mService.getMinJobExecutionGuaranteeMs(jobDef));
}
+
+ /**
+ * Confirm that {@link JobSchedulerService#getRescheduleJobForFailureLocked(JobStatus, int)}
+ * returns a job with the correct delay and deadline constraints.
+ */
+ @Test
+ public void testGetRescheduleJobForFailure() {
+ final long nowElapsed = sElapsedRealtimeClock.millis();
+ final long initialBackoffMs = MINUTE_IN_MILLIS;
+ mService.mConstants.SYSTEM_STOP_TO_FAILURE_RATIO = 3;
+
+ JobStatus originalJob = createJobStatus("testGetRescheduleJobForFailure",
+ createJobInfo()
+ .setBackoffCriteria(initialBackoffMs, JobInfo.BACKOFF_POLICY_LINEAR));
+ assertEquals(JobStatus.NO_EARLIEST_RUNTIME, originalJob.getEarliestRunTime());
+ assertEquals(JobStatus.NO_LATEST_RUNTIME, originalJob.getLatestRunTimeElapsed());
+
+ // failure = 0, systemStop = 1
+ JobStatus rescheduledJob = mService.getRescheduleJobForFailureLocked(originalJob,
+ JobParameters.INTERNAL_STOP_REASON_DEVICE_THERMAL);
+ assertEquals(nowElapsed + initialBackoffMs, rescheduledJob.getEarliestRunTime());
+ assertEquals(JobStatus.NO_LATEST_RUNTIME, rescheduledJob.getLatestRunTimeElapsed());
+
+ // failure = 0, systemStop = 2
+ rescheduledJob = mService.getRescheduleJobForFailureLocked(rescheduledJob,
+ JobParameters.INTERNAL_STOP_REASON_PREEMPT);
+ // failure = 0, systemStop = 3
+ rescheduledJob = mService.getRescheduleJobForFailureLocked(rescheduledJob,
+ JobParameters.INTERNAL_STOP_REASON_CONSTRAINTS_NOT_SATISFIED);
+ assertEquals(nowElapsed + initialBackoffMs, rescheduledJob.getEarliestRunTime());
+ assertEquals(JobStatus.NO_LATEST_RUNTIME, rescheduledJob.getLatestRunTimeElapsed());
+
+ // failure = 0, systemStop = 2 * SYSTEM_STOP_TO_FAILURE_RATIO
+ for (int i = 0; i < mService.mConstants.SYSTEM_STOP_TO_FAILURE_RATIO; ++i) {
+ rescheduledJob = mService.getRescheduleJobForFailureLocked(rescheduledJob,
+ JobParameters.INTERNAL_STOP_REASON_RTC_UPDATED);
+ }
+ assertEquals(nowElapsed + 2 * initialBackoffMs, rescheduledJob.getEarliestRunTime());
+ assertEquals(JobStatus.NO_LATEST_RUNTIME, rescheduledJob.getLatestRunTimeElapsed());
+
+ // failure = 1, systemStop = 2 * SYSTEM_STOP_TO_FAILURE_RATIO
+ rescheduledJob = mService.getRescheduleJobForFailureLocked(rescheduledJob,
+ JobParameters.INTERNAL_STOP_REASON_TIMEOUT);
+ assertEquals(nowElapsed + 3 * initialBackoffMs, rescheduledJob.getEarliestRunTime());
+ assertEquals(JobStatus.NO_LATEST_RUNTIME, rescheduledJob.getLatestRunTimeElapsed());
+
+ // failure = 2, systemStop = 2 * SYSTEM_STOP_TO_FAILURE_RATIO
+ rescheduledJob = mService.getRescheduleJobForFailureLocked(rescheduledJob,
+ JobParameters.INTERNAL_STOP_REASON_SUCCESSFUL_FINISH);
+ assertEquals(nowElapsed + 4 * initialBackoffMs, rescheduledJob.getEarliestRunTime());
+ assertEquals(JobStatus.NO_LATEST_RUNTIME, rescheduledJob.getLatestRunTimeElapsed());
+ }
+
/**
* Confirm that {@link JobSchedulerService#getRescheduleJobForPeriodic(JobStatus)} returns a job
* with the correct delay and deadline constraints if the periodic job is scheduled with the
@@ -544,14 +598,16 @@
final long nextWindowEndTime = now + 2 * HOUR_IN_MILLIS;
JobStatus job = createJobStatus("testGetRescheduleJobForPeriodic_insideWindow_failedJob",
createJobInfo().setPeriodic(HOUR_IN_MILLIS));
- JobStatus failedJob = mService.getRescheduleJobForFailureLocked(job);
+ JobStatus failedJob = mService.getRescheduleJobForFailureLocked(job,
+ JobParameters.INTERNAL_STOP_REASON_SUCCESSFUL_FINISH);
JobStatus rescheduledJob = mService.getRescheduleJobForPeriodic(failedJob);
assertEquals(nextWindowStartTime, rescheduledJob.getEarliestRunTime());
assertEquals(nextWindowEndTime, rescheduledJob.getLatestRunTimeElapsed());
advanceElapsedClock(5 * MINUTE_IN_MILLIS); // now + 5 minutes
- failedJob = mService.getRescheduleJobForFailureLocked(job);
+ failedJob = mService.getRescheduleJobForFailureLocked(job,
+ JobParameters.INTERNAL_STOP_REASON_SUCCESSFUL_FINISH);
advanceElapsedClock(5 * MINUTE_IN_MILLIS); // now + 10 minutes
rescheduledJob = mService.getRescheduleJobForPeriodic(failedJob);
@@ -559,7 +615,8 @@
assertEquals(nextWindowEndTime, rescheduledJob.getLatestRunTimeElapsed());
advanceElapsedClock(35 * MINUTE_IN_MILLIS); // now + 45 minutes
- failedJob = mService.getRescheduleJobForFailureLocked(job);
+ failedJob = mService.getRescheduleJobForFailureLocked(job,
+ JobParameters.INTERNAL_STOP_REASON_SUCCESSFUL_FINISH);
advanceElapsedClock(10 * MINUTE_IN_MILLIS); // now + 55 minutes
rescheduledJob = mService.getRescheduleJobForPeriodic(failedJob);
@@ -569,7 +626,8 @@
assertEquals(nextWindowEndTime, rescheduledJob.getLatestRunTimeElapsed());
advanceElapsedClock(2 * MINUTE_IN_MILLIS); // now + 57 minutes
- failedJob = mService.getRescheduleJobForFailureLocked(job);
+ failedJob = mService.getRescheduleJobForFailureLocked(job,
+ JobParameters.INTERNAL_STOP_REASON_SUCCESSFUL_FINISH);
advanceElapsedClock(2 * MINUTE_IN_MILLIS); // now + 59 minutes
rescheduledJob = mService.getRescheduleJobForPeriodic(failedJob);
@@ -665,7 +723,8 @@
public void testGetRescheduleJobForPeriodic_outsideWindow_failedJob() {
JobStatus job = createJobStatus("testGetRescheduleJobForPeriodic_outsideWindow_failedJob",
createJobInfo().setPeriodic(HOUR_IN_MILLIS));
- JobStatus failedJob = mService.getRescheduleJobForFailureLocked(job);
+ JobStatus failedJob = mService.getRescheduleJobForFailureLocked(job,
+ JobParameters.INTERNAL_STOP_REASON_SUCCESSFUL_FINISH);
long now = sElapsedRealtimeClock.millis();
long nextWindowStartTime = now + HOUR_IN_MILLIS;
long nextWindowEndTime = now + 2 * HOUR_IN_MILLIS;
@@ -701,7 +760,8 @@
JobStatus job = createJobStatus(
"testGetRescheduleJobForPeriodic_outsideWindow_flex_failedJob",
createJobInfo().setPeriodic(HOUR_IN_MILLIS, 30 * MINUTE_IN_MILLIS));
- JobStatus failedJob = mService.getRescheduleJobForFailureLocked(job);
+ JobStatus failedJob = mService.getRescheduleJobForFailureLocked(job,
+ JobParameters.INTERNAL_STOP_REASON_SUCCESSFUL_FINISH);
// First window starts 30 minutes from now.
advanceElapsedClock(30 * MINUTE_IN_MILLIS);
long now = sElapsedRealtimeClock.millis();
@@ -742,7 +802,8 @@
JobStatus job = createJobStatus(
"testGetRescheduleJobForPeriodic_outsideWindow_flex_failedJob_longPeriod",
createJobInfo().setPeriodic(7 * DAY_IN_MILLIS, 9 * HOUR_IN_MILLIS));
- JobStatus failedJob = mService.getRescheduleJobForFailureLocked(job);
+ JobStatus failedJob = mService.getRescheduleJobForFailureLocked(job,
+ JobParameters.INTERNAL_STOP_REASON_SUCCESSFUL_FINISH);
// First window starts 6.625 days from now.
advanceElapsedClock(6 * DAY_IN_MILLIS + 15 * HOUR_IN_MILLIS);
long now = sElapsedRealtimeClock.millis();
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/BatteryControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/BatteryControllerTest.java
index 59cb43f..7c435be 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/BatteryControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/BatteryControllerTest.java
@@ -432,10 +432,10 @@
assertFalse(topStartedJobs.contains(unrelatedJob));
// Job cleanup
- mBatteryController.maybeStopTrackingJobLocked(batteryJob, null, false);
- mBatteryController.maybeStopTrackingJobLocked(chargingJob, null, false);
- mBatteryController.maybeStopTrackingJobLocked(bothPowerJob, null, false);
- mBatteryController.maybeStopTrackingJobLocked(unrelatedJob, null, false);
+ mBatteryController.maybeStopTrackingJobLocked(batteryJob, null);
+ mBatteryController.maybeStopTrackingJobLocked(chargingJob, null);
+ mBatteryController.maybeStopTrackingJobLocked(bothPowerJob, null);
+ mBatteryController.maybeStopTrackingJobLocked(unrelatedJob, null);
assertFalse(trackedJobs.contains(batteryJob));
assertFalse(trackedJobs.contains(chargingJob));
assertFalse(trackedJobs.contains(bothPowerJob));
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/FlexibilityControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/FlexibilityControllerTest.java
index 674e500..3bee687 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/FlexibilityControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/FlexibilityControllerTest.java
@@ -489,19 +489,22 @@
JobInfo.Builder jb = createJob(0).setOverrideDeadline(1000L);
JobStatus js = createJobStatus("time", jb);
js = new JobStatus(
- js, FROZEN_TIME, NO_LATEST_RUNTIME, /* numFailures */ 2, FROZEN_TIME, FROZEN_TIME);
+ js, FROZEN_TIME, NO_LATEST_RUNTIME, /* numFailures */ 2, /* numSystemStops */ 0,
+ FROZEN_TIME, FROZEN_TIME);
assertEquals(mFcConfig.RESCHEDULED_JOB_DEADLINE_MS,
mFlexibilityController.getLifeCycleEndElapsedLocked(js, 0));
js = new JobStatus(
- js, FROZEN_TIME, NO_LATEST_RUNTIME, /* numFailures */ 3, FROZEN_TIME, FROZEN_TIME);
+ js, FROZEN_TIME, NO_LATEST_RUNTIME, /* numFailures */ 2, /* numSystemStops */ 1,
+ FROZEN_TIME, FROZEN_TIME);
assertEquals(2 * mFcConfig.RESCHEDULED_JOB_DEADLINE_MS,
mFlexibilityController.getLifeCycleEndElapsedLocked(js, 0));
js = new JobStatus(
- js, FROZEN_TIME, NO_LATEST_RUNTIME, /* numFailures */ 10, FROZEN_TIME, FROZEN_TIME);
+ js, FROZEN_TIME, NO_LATEST_RUNTIME, /* numFailures */ 0, /* numSystemStops */ 10,
+ FROZEN_TIME, FROZEN_TIME);
assertEquals(mFcConfig.MAX_RESCHEDULED_DEADLINE_MS,
mFlexibilityController.getLifeCycleEndElapsedLocked(js, 0));
}
@@ -637,7 +640,12 @@
JobInfo.Builder jb = createJob(0);
JobStatus js = createJobStatus("time", jb);
js = new JobStatus(
- js, FROZEN_TIME, NO_LATEST_RUNTIME, /* numFailures */ 1, FROZEN_TIME, FROZEN_TIME);
+ js, FROZEN_TIME, NO_LATEST_RUNTIME, /* numFailures */ 1, /* numSystemStops */ 0,
+ FROZEN_TIME, FROZEN_TIME);
+ assertFalse(js.hasFlexibilityConstraint());
+ js = new JobStatus(
+ js, FROZEN_TIME, NO_LATEST_RUNTIME, /* numFailures */ 0, /* numSystemStops */ 1,
+ FROZEN_TIME, FROZEN_TIME);
assertFalse(js.hasFlexibilityConstraint());
}
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 149ae0b..7f522b0 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
@@ -248,20 +248,32 @@
// Less than 2 failures, priority shouldn't be affected.
assertEquals(JobInfo.PRIORITY_MAX, job.getEffectivePriority());
- int backoffAttempt = 1;
- job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, backoffAttempt, 0, 0);
+ int numFailures = 1;
+ int numSystemStops = 0;
+ job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures,
+ numSystemStops, 0, 0);
assertEquals(JobInfo.PRIORITY_MAX, job.getEffectivePriority());
// 2+ failures, priority should be lowered as much as possible.
- backoffAttempt = 2;
- job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, backoffAttempt, 0, 0);
+ numFailures = 2;
+ job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures,
+ numSystemStops, 0, 0);
assertEquals(JobInfo.PRIORITY_HIGH, job.getEffectivePriority());
- backoffAttempt = 5;
- job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, backoffAttempt, 0, 0);
+ numFailures = 5;
+ job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures,
+ numSystemStops, 0, 0);
assertEquals(JobInfo.PRIORITY_HIGH, job.getEffectivePriority());
- backoffAttempt = 8;
- job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, backoffAttempt, 0, 0);
+ numFailures = 8;
+ job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures,
+ numSystemStops, 0, 0);
assertEquals(JobInfo.PRIORITY_HIGH, job.getEffectivePriority());
+
+ // System stops shouldn't factor in the downgrade.
+ numSystemStops = 10;
+ numFailures = 0;
+ job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures,
+ numSystemStops, 0, 0);
+ assertEquals(JobInfo.PRIORITY_MAX, job.getEffectivePriority());
}
@Test
@@ -274,33 +286,48 @@
// Less than 2 failures, priority shouldn't be affected.
assertEquals(JobInfo.PRIORITY_HIGH, job.getEffectivePriority());
- int backoffAttempt = 1;
- job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, backoffAttempt, 0, 0);
+ int numFailures = 1;
+ int numSystemStops = 0;
+ job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures,
+ numSystemStops, 0, 0);
assertEquals(JobInfo.PRIORITY_HIGH, job.getEffectivePriority());
// Failures in [2,4), priority should be lowered slightly.
- backoffAttempt = 2;
- job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, backoffAttempt, 0, 0);
+ numFailures = 2;
+ job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures,
+ numSystemStops, 0, 0);
assertEquals(JobInfo.PRIORITY_DEFAULT, job.getEffectivePriority());
- backoffAttempt = 3;
- job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, backoffAttempt, 0, 0);
+ numFailures = 3;
+ job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures,
+ numSystemStops, 0, 0);
assertEquals(JobInfo.PRIORITY_DEFAULT, job.getEffectivePriority());
// Failures in [4,6), priority should be lowered more.
- backoffAttempt = 4;
- job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, backoffAttempt, 0, 0);
+ numFailures = 4;
+ job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures,
+ numSystemStops, 0, 0);
assertEquals(JobInfo.PRIORITY_LOW, job.getEffectivePriority());
- backoffAttempt = 5;
- job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, backoffAttempt, 0, 0);
+ numFailures = 5;
+ job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures,
+ numSystemStops, 0, 0);
assertEquals(JobInfo.PRIORITY_LOW, job.getEffectivePriority());
// 6+ failures, priority should be lowered as much as possible.
- backoffAttempt = 6;
- job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, backoffAttempt, 0, 0);
+ numFailures = 6;
+ job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures,
+ numSystemStops, 0, 0);
assertEquals(JobInfo.PRIORITY_MIN, job.getEffectivePriority());
- backoffAttempt = 12;
- job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, backoffAttempt, 0, 0);
+ numFailures = 12;
+ job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures,
+ numSystemStops, 0, 0);
assertEquals(JobInfo.PRIORITY_MIN, job.getEffectivePriority());
+
+ // System stops shouldn't factor in the downgrade.
+ numSystemStops = 10;
+ numFailures = 0;
+ job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures,
+ numSystemStops, 0, 0);
+ assertEquals(JobInfo.PRIORITY_HIGH, job.getEffectivePriority());
}
/**
@@ -317,23 +344,36 @@
// Less than 6 failures, priority shouldn't be affected.
assertEquals(JobInfo.PRIORITY_LOW, job.getEffectivePriority());
- int backoffAttempt = 1;
- job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, backoffAttempt, 0, 0);
+ int numFailures = 1;
+ int numSystemStops = 0;
+ job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures,
+ numSystemStops, 0, 0);
assertEquals(JobInfo.PRIORITY_LOW, job.getEffectivePriority());
- backoffAttempt = 4;
- job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, backoffAttempt, 0, 0);
+ numFailures = 4;
+ job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures,
+ numSystemStops, 0, 0);
assertEquals(JobInfo.PRIORITY_LOW, job.getEffectivePriority());
- backoffAttempt = 5;
- job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, backoffAttempt, 0, 0);
+ numFailures = 5;
+ job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures,
+ numSystemStops, 0, 0);
assertEquals(JobInfo.PRIORITY_LOW, job.getEffectivePriority());
// 6+ failures, priority should be lowered as much as possible.
- backoffAttempt = 6;
- job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, backoffAttempt, 0, 0);
+ numFailures = 6;
+ job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures,
+ numSystemStops, 0, 0);
assertEquals(JobInfo.PRIORITY_MIN, job.getEffectivePriority());
- backoffAttempt = 12;
- job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, backoffAttempt, 0, 0);
+ numFailures = 12;
+ job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures,
+ numSystemStops, 0, 0);
assertEquals(JobInfo.PRIORITY_MIN, job.getEffectivePriority());
+
+ // System stops shouldn't factor in the downgrade.
+ numSystemStops = 10;
+ numFailures = 0;
+ job = new JobStatus(job, NO_EARLIEST_RUNTIME, NO_LATEST_RUNTIME, numFailures,
+ numSystemStops, 0, 0);
+ assertEquals(JobInfo.PRIORITY_LOW, job.getEffectivePriority());
}
/**
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/PrefetchControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/PrefetchControllerTest.java
index bb477b1..b949b3b 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/PrefetchControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/PrefetchControllerTest.java
@@ -47,6 +47,7 @@
import android.appwidget.AppWidgetManager;
import android.content.ComponentName;
import android.content.Context;
+import android.os.Handler;
import android.os.Looper;
import android.os.Process;
import android.os.SystemClock;
@@ -276,13 +277,13 @@
inOrder.verify(mAlarmManager, timeout(DEFAULT_WAIT_MS).times(1))
.setWindow(
anyInt(), eq(sElapsedRealtimeClock.millis() + 4 * HOUR_IN_MILLIS),
- anyLong(), eq(TAG_PREFETCH), any(), any());
+ anyLong(), eq(TAG_PREFETCH), any(), any(Handler.class));
setDeviceConfigLong(PcConstants.KEY_LAUNCH_TIME_THRESHOLD_MS, 3 * HOUR_IN_MILLIS);
inOrder.verify(mAlarmManager, timeout(DEFAULT_WAIT_MS).times(1))
.setWindow(
anyInt(), eq(sElapsedRealtimeClock.millis() + 8 * HOUR_IN_MILLIS),
- anyLong(), eq(TAG_PREFETCH), any(), any());
+ anyLong(), eq(TAG_PREFETCH), any(), any(Handler.class));
}
@Test
@@ -414,7 +415,7 @@
verify(mAlarmManager, timeout(DEFAULT_WAIT_MS).times(1))
.setWindow(
anyInt(), eq(sElapsedRealtimeClock.millis() + 3 * HOUR_IN_MILLIS),
- anyLong(), eq(TAG_PREFETCH), any(), any());
+ anyLong(), eq(TAG_PREFETCH), any(), any(Handler.class));
assertFalse(jobStatus.isConstraintSatisfied(JobStatus.CONSTRAINT_PREFETCH));
assertFalse(jobStatus.isReady());
}
@@ -464,7 +465,7 @@
verify(mAlarmManager, timeout(DEFAULT_WAIT_MS).times(1))
.setWindow(
anyInt(), eq(sElapsedRealtimeClock.millis() + 3 * HOUR_IN_MILLIS),
- anyLong(), eq(TAG_PREFETCH), any(), any());
+ anyLong(), eq(TAG_PREFETCH), any(), any(Handler.class));
assertFalse(jobStatus.isConstraintSatisfied(JobStatus.CONSTRAINT_PREFETCH));
assertFalse(jobStatus.isReady());
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
index 9407968..17822c6 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
@@ -1356,7 +1356,7 @@
synchronized (mQuotaController.mLock) {
assertEquals(JobSchedulerService.Constants.DEFAULT_RUNTIME_FREE_QUOTA_MAX_LIMIT_MS,
mQuotaController.getMaxJobExecutionTimeMsLocked((job)));
- mQuotaController.maybeStopTrackingJobLocked(job, null, false);
+ mQuotaController.maybeStopTrackingJobLocked(job, null);
}
setProcessState(ActivityManager.PROCESS_STATE_RECEIVER);
@@ -1441,7 +1441,7 @@
synchronized (mQuotaController.mLock) {
assertEquals(mQcConstants.EJ_LIMIT_ACTIVE_MS / 2,
mQuotaController.getMaxJobExecutionTimeMsLocked(job));
- mQuotaController.maybeStopTrackingJobLocked(job, null, false);
+ mQuotaController.maybeStopTrackingJobLocked(job, null);
}
setProcessState(ActivityManager.PROCESS_STATE_RECEIVER);
@@ -1474,7 +1474,7 @@
synchronized (mQuotaController.mLock) {
assertEquals(mQcConstants.EJ_LIMIT_ACTIVE_MS / 2,
mQuotaController.getMaxJobExecutionTimeMsLocked(job));
- mQuotaController.maybeStopTrackingJobLocked(job, null, false);
+ mQuotaController.maybeStopTrackingJobLocked(job, null);
}
setProcessState(ActivityManager.PROCESS_STATE_RECEIVER);
@@ -2017,7 +2017,7 @@
setProcessState(ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND);
}
synchronized (mQuotaController.mLock) {
- mQuotaController.maybeStopTrackingJobLocked(jobStatus, null, false);
+ mQuotaController.maybeStopTrackingJobLocked(jobStatus, null);
}
advanceElapsedClock(15 * SECOND_IN_MILLIS);
@@ -2032,7 +2032,7 @@
setProcessState(ActivityManager.PROCESS_STATE_RECEIVER);
}
synchronized (mQuotaController.mLock) {
- mQuotaController.maybeStopTrackingJobLocked(jobStatus, null, false);
+ mQuotaController.maybeStopTrackingJobLocked(jobStatus, null);
}
advanceElapsedClock(10 * MINUTE_IN_MILLIS + 30 * SECOND_IN_MILLIS);
@@ -2090,7 +2090,7 @@
setProcessState(ActivityManager.PROCESS_STATE_TOP_SLEEPING, fgChangerUid);
}
synchronized (mQuotaController.mLock) {
- mQuotaController.maybeStopTrackingJobLocked(fgStateChanger, null, false);
+ mQuotaController.maybeStopTrackingJobLocked(fgStateChanger, null);
}
advanceElapsedClock(15 * SECOND_IN_MILLIS);
@@ -2105,9 +2105,9 @@
setProcessState(ActivityManager.PROCESS_STATE_TOP_SLEEPING, fgChangerUid);
}
synchronized (mQuotaController.mLock) {
- mQuotaController.maybeStopTrackingJobLocked(fgStateChanger, null, false);
+ mQuotaController.maybeStopTrackingJobLocked(fgStateChanger, null);
- mQuotaController.maybeStopTrackingJobLocked(unaffected, null, false);
+ mQuotaController.maybeStopTrackingJobLocked(unaffected, null);
assertTrue(mQuotaController.isWithinQuotaLocked(unaffected));
assertTrue(unaffected.isReady());
@@ -2226,8 +2226,8 @@
advanceElapsedClock(MINUTE_IN_MILLIS);
synchronized (mQuotaController.mLock) {
- mQuotaController.maybeStopTrackingJobLocked(job1, null, false);
- mQuotaController.maybeStopTrackingJobLocked(job2, null, false);
+ mQuotaController.maybeStopTrackingJobLocked(job1, null);
+ mQuotaController.maybeStopTrackingJobLocked(job2, null);
assertFalse(mQuotaController
.isWithinQuotaLocked(SOURCE_USER_ID, SOURCE_PACKAGE, WORKING_INDEX));
assertEquals(7 * MINUTE_IN_MILLIS, stats.allowedTimePerPeriodMs);
@@ -2312,8 +2312,8 @@
advanceElapsedClock(MINUTE_IN_MILLIS);
synchronized (mQuotaController.mLock) {
- mQuotaController.maybeStopTrackingJobLocked(job1, null, false);
- mQuotaController.maybeStopTrackingJobLocked(job2, null, false);
+ mQuotaController.maybeStopTrackingJobLocked(job1, null);
+ mQuotaController.maybeStopTrackingJobLocked(job2, null);
assertFalse(mQuotaController
.isWithinQuotaLocked(SOURCE_USER_ID, SOURCE_PACKAGE, WORKING_INDEX));
assertEquals(12, stats.jobCountLimit);
@@ -2390,7 +2390,7 @@
advanceElapsedClock(MINUTE_IN_MILLIS);
mAppIdleStateChangeListener.triggerTemporaryQuotaBump(SOURCE_PACKAGE, SOURCE_USER_ID);
synchronized (mQuotaController.mLock) {
- mQuotaController.maybeStopTrackingJobLocked(job1, null, false);
+ mQuotaController.maybeStopTrackingJobLocked(job1, null);
assertTrue(mQuotaController
.isWithinQuotaLocked(SOURCE_USER_ID, SOURCE_PACKAGE, WORKING_INDEX));
assertEquals(4, stats.sessionCountLimit);
@@ -2404,7 +2404,7 @@
advanceElapsedClock(MINUTE_IN_MILLIS);
synchronized (mQuotaController.mLock) {
- mQuotaController.maybeStopTrackingJobLocked(job2, null, false);
+ mQuotaController.maybeStopTrackingJobLocked(job2, null);
assertFalse(mQuotaController
.isWithinQuotaLocked(SOURCE_USER_ID, SOURCE_PACKAGE, WORKING_INDEX));
assertEquals(4, stats.sessionCountLimit);
@@ -2708,7 +2708,7 @@
SOURCE_USER_ID, SOURCE_PACKAGE, standbyBucket);
}
verify(mAlarmManager, timeout(1000).times(0)).setWindow(
- anyInt(), anyLong(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any());
+ anyInt(), anyLong(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any(Handler.class));
final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
// Test with timing sessions out of window but still under max execution limit.
@@ -2725,7 +2725,7 @@
SOURCE_USER_ID, SOURCE_PACKAGE, standbyBucket);
}
verify(mAlarmManager, timeout(1000).times(0)).setWindow(
- anyInt(), anyLong(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any());
+ anyInt(), anyLong(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any(Handler.class));
mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
createTimingSession(now - 2 * HOUR_IN_MILLIS, 55 * MINUTE_IN_MILLIS, 1), false);
@@ -2734,7 +2734,7 @@
SOURCE_USER_ID, SOURCE_PACKAGE, standbyBucket);
}
verify(mAlarmManager, timeout(1000).times(0)).setWindow(
- anyInt(), anyLong(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any());
+ anyInt(), anyLong(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any(Handler.class));
synchronized (mQuotaController.mLock) {
mQuotaController.prepareForExecutionLocked(jobStatus);
@@ -2749,7 +2749,8 @@
SOURCE_USER_ID, SOURCE_PACKAGE, standbyBucket);
}
verify(mAlarmManager, timeout(1000).times(1)).setWindow(
- anyInt(), eq(expectedAlarmTime), anyLong(), eq(TAG_QUOTA_CHECK), any(), any());
+ anyInt(), eq(expectedAlarmTime), anyLong(), eq(TAG_QUOTA_CHECK), any(),
+ any(Handler.class));
}
@Test
@@ -2771,7 +2772,7 @@
SOURCE_USER_ID, SOURCE_PACKAGE, standbyBucket);
}
verify(mAlarmManager, timeout(1000).times(0)).setWindow(
- anyInt(), anyLong(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any());
+ anyInt(), anyLong(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any(Handler.class));
// Test with timing sessions out of window.
final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
@@ -2782,7 +2783,7 @@
SOURCE_USER_ID, SOURCE_PACKAGE, standbyBucket);
}
verify(mAlarmManager, timeout(1000).times(0)).setWindow(
- anyInt(), anyLong(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any());
+ anyInt(), anyLong(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any(Handler.class));
// Test with timing sessions in window but still in quota.
final long end = now - (2 * HOUR_IN_MILLIS - 5 * MINUTE_IN_MILLIS);
@@ -2796,7 +2797,7 @@
SOURCE_USER_ID, SOURCE_PACKAGE, standbyBucket);
}
verify(mAlarmManager, timeout(1000).times(0)).setWindow(
- anyInt(), anyLong(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any());
+ anyInt(), anyLong(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any(Handler.class));
// Add some more sessions, but still in quota.
mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
@@ -2808,7 +2809,7 @@
SOURCE_USER_ID, SOURCE_PACKAGE, standbyBucket);
}
verify(mAlarmManager, timeout(1000).times(0)).setWindow(
- anyInt(), anyLong(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any());
+ anyInt(), anyLong(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any(Handler.class));
// Test when out of quota.
mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
@@ -2818,7 +2819,8 @@
SOURCE_USER_ID, SOURCE_PACKAGE, standbyBucket);
}
verify(mAlarmManager, timeout(1000).times(1)).setWindow(
- anyInt(), eq(expectedAlarmTime), anyLong(), eq(TAG_QUOTA_CHECK), any(), any());
+ anyInt(), eq(expectedAlarmTime), anyLong(), eq(TAG_QUOTA_CHECK), any(),
+ any(Handler.class));
// Alarm already scheduled, so make sure it's not scheduled again.
synchronized (mQuotaController.mLock) {
@@ -2826,7 +2828,8 @@
SOURCE_USER_ID, SOURCE_PACKAGE, standbyBucket);
}
verify(mAlarmManager, timeout(1000).times(1)).setWindow(
- anyInt(), eq(expectedAlarmTime), anyLong(), eq(TAG_QUOTA_CHECK), any(), any());
+ anyInt(), eq(expectedAlarmTime), anyLong(), eq(TAG_QUOTA_CHECK), any(),
+ any(Handler.class));
}
@Test
@@ -2850,7 +2853,7 @@
SOURCE_USER_ID, SOURCE_PACKAGE, standbyBucket);
}
verify(mAlarmManager, timeout(1000).times(0)).setWindow(
- anyInt(), anyLong(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any());
+ anyInt(), anyLong(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any(Handler.class));
// Test with timing sessions out of window.
final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
@@ -2861,7 +2864,7 @@
SOURCE_USER_ID, SOURCE_PACKAGE, standbyBucket);
}
verify(mAlarmManager, timeout(1000).times(0)).setWindow(
- anyInt(), anyLong(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any());
+ anyInt(), anyLong(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any(Handler.class));
// Test with timing sessions in window but still in quota.
final long start = now - (6 * HOUR_IN_MILLIS);
@@ -2873,7 +2876,7 @@
SOURCE_USER_ID, SOURCE_PACKAGE, standbyBucket);
}
verify(mAlarmManager, timeout(1000).times(0)).setWindow(
- anyInt(), anyLong(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any());
+ anyInt(), anyLong(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any(Handler.class));
// Add some more sessions, but still in quota.
mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
@@ -2885,7 +2888,7 @@
SOURCE_USER_ID, SOURCE_PACKAGE, standbyBucket);
}
verify(mAlarmManager, timeout(1000).times(0)).setWindow(
- anyInt(), anyLong(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any());
+ anyInt(), anyLong(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any(Handler.class));
// Test when out of quota.
mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
@@ -2895,7 +2898,8 @@
SOURCE_USER_ID, SOURCE_PACKAGE, standbyBucket);
}
verify(mAlarmManager, timeout(1000).times(1)).setWindow(
- anyInt(), eq(expectedAlarmTime), anyLong(), eq(TAG_QUOTA_CHECK), any(), any());
+ anyInt(), eq(expectedAlarmTime), anyLong(), eq(TAG_QUOTA_CHECK), any(),
+ any(Handler.class));
// Alarm already scheduled, so make sure it's not scheduled again.
synchronized (mQuotaController.mLock) {
@@ -2903,7 +2907,8 @@
SOURCE_USER_ID, SOURCE_PACKAGE, standbyBucket);
}
verify(mAlarmManager, timeout(1000).times(1)).setWindow(
- anyInt(), eq(expectedAlarmTime), anyLong(), eq(TAG_QUOTA_CHECK), any(), any());
+ anyInt(), eq(expectedAlarmTime), anyLong(), eq(TAG_QUOTA_CHECK), any(),
+ any(Handler.class));
}
/**
@@ -2932,7 +2937,7 @@
SOURCE_USER_ID, SOURCE_PACKAGE, effectiveStandbyBucket);
}
verify(mAlarmManager, timeout(1000).times(0)).setWindow(
- anyInt(), anyLong(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any());
+ anyInt(), anyLong(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any(Handler.class));
// Test with timing sessions out of window.
final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
@@ -2943,7 +2948,7 @@
SOURCE_USER_ID, SOURCE_PACKAGE, effectiveStandbyBucket);
}
verify(mAlarmManager, timeout(1000).times(0)).setWindow(
- anyInt(), anyLong(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any());
+ anyInt(), anyLong(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any(Handler.class));
// Test with timing sessions in window but still in quota.
final long start = now - (6 * HOUR_IN_MILLIS);
@@ -2955,7 +2960,7 @@
SOURCE_USER_ID, SOURCE_PACKAGE, effectiveStandbyBucket);
}
verify(mAlarmManager, timeout(1000).times(0)).setWindow(
- anyInt(), anyLong(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any());
+ anyInt(), anyLong(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any(Handler.class));
// Add some more sessions, but still in quota.
mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
@@ -2967,7 +2972,7 @@
SOURCE_USER_ID, SOURCE_PACKAGE, effectiveStandbyBucket);
}
verify(mAlarmManager, timeout(1000).times(0)).setWindow(
- anyInt(), anyLong(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any());
+ anyInt(), anyLong(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any(Handler.class));
// Test when out of quota.
mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
@@ -2977,7 +2982,8 @@
SOURCE_USER_ID, SOURCE_PACKAGE, effectiveStandbyBucket);
}
verify(mAlarmManager, timeout(1000).times(1)).setWindow(
- anyInt(), eq(expectedAlarmTime), anyLong(), eq(TAG_QUOTA_CHECK), any(), any());
+ anyInt(), eq(expectedAlarmTime), anyLong(), eq(TAG_QUOTA_CHECK), any(),
+ any(Handler.class));
// Alarm already scheduled, so make sure it's not scheduled again.
synchronized (mQuotaController.mLock) {
@@ -2985,7 +2991,8 @@
SOURCE_USER_ID, SOURCE_PACKAGE, effectiveStandbyBucket);
}
verify(mAlarmManager, timeout(1000).times(1)).setWindow(
- anyInt(), eq(expectedAlarmTime), anyLong(), eq(TAG_QUOTA_CHECK), any(), any());
+ anyInt(), eq(expectedAlarmTime), anyLong(), eq(TAG_QUOTA_CHECK), any(),
+ any(Handler.class));
}
@Test
@@ -3013,7 +3020,7 @@
SOURCE_USER_ID, SOURCE_PACKAGE, standbyBucket);
}
verify(mAlarmManager, timeout(1000).times(0)).setWindow(
- anyInt(), anyLong(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any());
+ anyInt(), anyLong(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any(Handler.class));
// Test with timing sessions out of window.
final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
@@ -3023,7 +3030,7 @@
mQuotaController.maybeScheduleStartAlarmLocked(0, "com.android.test", standbyBucket);
}
verify(mAlarmManager, timeout(1000).times(0)).setWindow(
- anyInt(), anyLong(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any());
+ anyInt(), anyLong(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any(Handler.class));
// Test with timing sessions in window but still in quota.
final long start = now - (6 * HOUR_IN_MILLIS);
@@ -3039,7 +3046,7 @@
SOURCE_USER_ID, SOURCE_PACKAGE, standbyBucket);
}
verify(mAlarmManager, timeout(1000).times(0)).setWindow(
- anyInt(), anyLong(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any());
+ anyInt(), anyLong(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any(Handler.class));
// Add some more sessions, but still in quota.
mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
@@ -3051,7 +3058,7 @@
SOURCE_USER_ID, SOURCE_PACKAGE, standbyBucket);
}
verify(mAlarmManager, timeout(1000).times(0)).setWindow(
- anyInt(), anyLong(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any());
+ anyInt(), anyLong(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any(Handler.class));
// Test when out of quota.
mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
@@ -3061,7 +3068,8 @@
SOURCE_USER_ID, SOURCE_PACKAGE, standbyBucket);
}
verify(mAlarmManager, timeout(1000).times(1)).setWindow(
- anyInt(), eq(expectedAlarmTime), anyLong(), eq(TAG_QUOTA_CHECK), any(), any());
+ anyInt(), eq(expectedAlarmTime), anyLong(), eq(TAG_QUOTA_CHECK), any(),
+ any(Handler.class));
// Alarm already scheduled, so make sure it's not scheduled again.
synchronized (mQuotaController.mLock) {
@@ -3069,7 +3077,8 @@
SOURCE_USER_ID, SOURCE_PACKAGE, standbyBucket);
}
verify(mAlarmManager, timeout(1000).times(1)).setWindow(
- anyInt(), eq(expectedAlarmTime), anyLong(), eq(TAG_QUOTA_CHECK), any(), any());
+ anyInt(), eq(expectedAlarmTime), anyLong(), eq(TAG_QUOTA_CHECK), any(),
+ any(Handler.class));
}
/** Tests that the start alarm is properly rescheduled if the app's bucket is changed. */
@@ -3108,7 +3117,8 @@
SOURCE_USER_ID, SOURCE_PACKAGE, ACTIVE_INDEX);
}
inOrder.verify(mAlarmManager, timeout(1000).times(0))
- .setWindow(anyInt(), anyLong(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any());
+ .setWindow(anyInt(), anyLong(), anyLong(), eq(TAG_QUOTA_CHECK), any(),
+ any(Handler.class));
inOrder.verify(mAlarmManager, timeout(1000).times(0))
.cancel(any(AlarmManager.OnAlarmListener.class));
@@ -3123,7 +3133,7 @@
}
inOrder.verify(mAlarmManager, timeout(1000).times(1)).setWindow(
anyInt(), eq(expectedWorkingAlarmTime), anyLong(),
- eq(TAG_QUOTA_CHECK), any(), any());
+ eq(TAG_QUOTA_CHECK), any(), any(Handler.class));
final long expectedFrequentAlarmTime =
outOfQuotaTime + (8 * HOUR_IN_MILLIS)
@@ -3135,7 +3145,7 @@
}
inOrder.verify(mAlarmManager, timeout(1000).times(1)).setWindow(
anyInt(), eq(expectedFrequentAlarmTime), anyLong(),
- eq(TAG_QUOTA_CHECK), any(), any());
+ eq(TAG_QUOTA_CHECK), any(), any(Handler.class));
final long expectedRareAlarmTime =
outOfQuotaTime + (24 * HOUR_IN_MILLIS)
@@ -3146,7 +3156,8 @@
SOURCE_USER_ID, SOURCE_PACKAGE, RARE_INDEX);
}
inOrder.verify(mAlarmManager, timeout(1000).times(1)).setWindow(
- anyInt(), eq(expectedRareAlarmTime), anyLong(), eq(TAG_QUOTA_CHECK), any(), any());
+ anyInt(), eq(expectedRareAlarmTime), anyLong(), eq(TAG_QUOTA_CHECK), any(),
+ any(Handler.class));
// And back up again.
setStandbyBucket(FREQUENT_INDEX, jobStatus);
@@ -3156,7 +3167,7 @@
}
inOrder.verify(mAlarmManager, timeout(1000).times(1)).setWindow(
anyInt(), eq(expectedFrequentAlarmTime), anyLong(),
- eq(TAG_QUOTA_CHECK), any(), any());
+ eq(TAG_QUOTA_CHECK), any(), any(Handler.class));
setStandbyBucket(WORKING_INDEX, jobStatus);
synchronized (mQuotaController.mLock) {
@@ -3165,7 +3176,7 @@
}
inOrder.verify(mAlarmManager, timeout(1000).times(1)).setWindow(
anyInt(), eq(expectedWorkingAlarmTime), anyLong(),
- eq(TAG_QUOTA_CHECK), any(), any());
+ eq(TAG_QUOTA_CHECK), any(), any(Handler.class));
setStandbyBucket(ACTIVE_INDEX, jobStatus);
synchronized (mQuotaController.mLock) {
@@ -3173,7 +3184,8 @@
SOURCE_USER_ID, SOURCE_PACKAGE, ACTIVE_INDEX);
}
inOrder.verify(mAlarmManager, timeout(1000).times(0))
- .setWindow(anyInt(), anyLong(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any());
+ .setWindow(anyInt(), anyLong(), anyLong(), eq(TAG_QUOTA_CHECK), any(),
+ any(Handler.class));
inOrder.verify(mAlarmManager, timeout(1000).times(1))
.cancel(any(AlarmManager.OnAlarmListener.class));
}
@@ -3210,7 +3222,7 @@
SOURCE_USER_ID, SOURCE_PACKAGE, standbyBucket);
}
verify(mAlarmManager, timeout(1000).times(0)).setWindow(
- anyInt(), anyLong(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any());
+ anyInt(), anyLong(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any(Handler.class));
// Valid time in the future, so the count should be used.
stats.jobRateLimitExpirationTimeElapsed = now + 5 * MINUTE_IN_MILLIS / 2;
@@ -3221,7 +3233,7 @@
}
verify(mAlarmManager, timeout(1000).times(1)).setWindow(
anyInt(), eq(expectedWorkingAlarmTime), anyLong(),
- eq(TAG_QUOTA_CHECK), any(), any());
+ eq(TAG_QUOTA_CHECK), any(), any(Handler.class));
}
/**
@@ -3318,7 +3330,8 @@
SOURCE_USER_ID, SOURCE_PACKAGE, standbyBucket);
}
verify(mAlarmManager, timeout(1000).times(1)).setWindow(
- anyInt(), eq(expectedAlarmTime), anyLong(), eq(TAG_QUOTA_CHECK), any(), any());
+ anyInt(), eq(expectedAlarmTime), anyLong(), eq(TAG_QUOTA_CHECK), any(),
+ any(Handler.class));
}
private void runTestMaybeScheduleStartAlarmLocked_SmallRollingQuota_MaxTimeCheck() {
@@ -3355,7 +3368,8 @@
SOURCE_USER_ID, SOURCE_PACKAGE, standbyBucket);
}
verify(mAlarmManager, timeout(1000).times(1)).setWindow(
- anyInt(), eq(expectedAlarmTime), anyLong(), eq(TAG_QUOTA_CHECK), any(), any());
+ anyInt(), eq(expectedAlarmTime), anyLong(), eq(TAG_QUOTA_CHECK), any(),
+ any(Handler.class));
}
@Test
@@ -3711,7 +3725,7 @@
}
advanceElapsedClock(5 * SECOND_IN_MILLIS);
synchronized (mQuotaController.mLock) {
- mQuotaController.maybeStopTrackingJobLocked(jobStatus, null, false);
+ mQuotaController.maybeStopTrackingJobLocked(jobStatus, null);
}
assertNull(mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
}
@@ -3737,7 +3751,7 @@
}
advanceElapsedClock(5 * SECOND_IN_MILLIS);
synchronized (mQuotaController.mLock) {
- mQuotaController.maybeStopTrackingJobLocked(jobStatus, null, false);
+ mQuotaController.maybeStopTrackingJobLocked(jobStatus, null);
}
expected.add(createTimingSession(start, 5 * SECOND_IN_MILLIS, 1));
assertEquals(expected, mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
@@ -3766,7 +3780,7 @@
}
advanceElapsedClock(10 * SECOND_IN_MILLIS);
synchronized (mQuotaController.mLock) {
- mQuotaController.maybeStopTrackingJobLocked(jobStatus, null, false);
+ mQuotaController.maybeStopTrackingJobLocked(jobStatus, null);
}
advanceElapsedClock(10 * SECOND_IN_MILLIS);
synchronized (mQuotaController.mLock) {
@@ -3774,11 +3788,11 @@
}
advanceElapsedClock(20 * SECOND_IN_MILLIS);
synchronized (mQuotaController.mLock) {
- mQuotaController.maybeStopTrackingJobLocked(jobStatus3, null, false);
+ mQuotaController.maybeStopTrackingJobLocked(jobStatus3, null);
}
advanceElapsedClock(10 * SECOND_IN_MILLIS);
synchronized (mQuotaController.mLock) {
- mQuotaController.maybeStopTrackingJobLocked(jobStatus2, null, false);
+ mQuotaController.maybeStopTrackingJobLocked(jobStatus2, null);
}
expected.add(createTimingSession(start, MINUTE_IN_MILLIS, 3));
assertEquals(expected, mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
@@ -3819,7 +3833,7 @@
long start = JobSchedulerService.sElapsedRealtimeClock.millis();
advanceElapsedClock(10 * SECOND_IN_MILLIS);
synchronized (mQuotaController.mLock) {
- mQuotaController.maybeStopTrackingJobLocked(jobStatus, jobStatus, true);
+ mQuotaController.maybeStopTrackingJobLocked(jobStatus, jobStatus);
}
expected.add(createTimingSession(start, 10 * SECOND_IN_MILLIS, 1));
assertEquals(expected, mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
@@ -3850,18 +3864,18 @@
}
advanceElapsedClock(10 * SECOND_IN_MILLIS);
synchronized (mQuotaController.mLock) {
- mQuotaController.maybeStopTrackingJobLocked(jobStatus3, null, false);
+ mQuotaController.maybeStopTrackingJobLocked(jobStatus3, null);
}
advanceElapsedClock(10 * SECOND_IN_MILLIS);
synchronized (mQuotaController.mLock) {
- mQuotaController.maybeStopTrackingJobLocked(jobStatus2, null, false);
+ mQuotaController.maybeStopTrackingJobLocked(jobStatus2, null);
}
advanceElapsedClock(10 * SECOND_IN_MILLIS);
setDischarging();
start = JobSchedulerService.sElapsedRealtimeClock.millis();
advanceElapsedClock(20 * SECOND_IN_MILLIS);
synchronized (mQuotaController.mLock) {
- mQuotaController.maybeStopTrackingJobLocked(jobStatus, null, false);
+ mQuotaController.maybeStopTrackingJobLocked(jobStatus, null);
}
expected.add(createTimingSession(start, 20 * SECOND_IN_MILLIS, 1));
assertEquals(expected, mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
@@ -3879,7 +3893,7 @@
setCharging();
advanceElapsedClock(10 * SECOND_IN_MILLIS);
synchronized (mQuotaController.mLock) {
- mQuotaController.maybeStopTrackingJobLocked(jobStatus2, null, false);
+ mQuotaController.maybeStopTrackingJobLocked(jobStatus2, null);
}
assertEquals(expected, mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
}
@@ -3905,7 +3919,7 @@
}
advanceElapsedClock(5 * SECOND_IN_MILLIS);
synchronized (mQuotaController.mLock) {
- mQuotaController.maybeStopTrackingJobLocked(jobStatus, null, false);
+ mQuotaController.maybeStopTrackingJobLocked(jobStatus, null);
}
expected.add(createTimingSession(start, 5 * SECOND_IN_MILLIS, 1));
assertEquals(expected, mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
@@ -3934,7 +3948,7 @@
}
advanceElapsedClock(10 * SECOND_IN_MILLIS);
synchronized (mQuotaController.mLock) {
- mQuotaController.maybeStopTrackingJobLocked(jobStatus, null, false);
+ mQuotaController.maybeStopTrackingJobLocked(jobStatus, null);
}
advanceElapsedClock(10 * SECOND_IN_MILLIS);
synchronized (mQuotaController.mLock) {
@@ -3942,11 +3956,11 @@
}
advanceElapsedClock(20 * SECOND_IN_MILLIS);
synchronized (mQuotaController.mLock) {
- mQuotaController.maybeStopTrackingJobLocked(jobStatus3, null, false);
+ mQuotaController.maybeStopTrackingJobLocked(jobStatus3, null);
}
advanceElapsedClock(10 * SECOND_IN_MILLIS);
synchronized (mQuotaController.mLock) {
- mQuotaController.maybeStopTrackingJobLocked(jobStatus2, null, false);
+ mQuotaController.maybeStopTrackingJobLocked(jobStatus2, null);
}
expected.add(createTimingSession(start, MINUTE_IN_MILLIS, 3));
assertEquals(expected, mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
@@ -3973,7 +3987,7 @@
setProcessState(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
advanceElapsedClock(5 * SECOND_IN_MILLIS);
synchronized (mQuotaController.mLock) {
- mQuotaController.maybeStopTrackingJobLocked(jobStatus, null, false);
+ mQuotaController.maybeStopTrackingJobLocked(jobStatus, null);
}
assertNull(mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
}
@@ -4005,7 +4019,7 @@
}
advanceElapsedClock(10 * SECOND_IN_MILLIS);
synchronized (mQuotaController.mLock) {
- mQuotaController.maybeStopTrackingJobLocked(jobBg1, jobBg1, true);
+ mQuotaController.maybeStopTrackingJobLocked(jobBg1, jobBg1);
}
expected.add(createTimingSession(start, 10 * SECOND_IN_MILLIS, 1));
assertEquals(expected, mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
@@ -4030,11 +4044,11 @@
}
advanceElapsedClock(10 * SECOND_IN_MILLIS);
synchronized (mQuotaController.mLock) {
- mQuotaController.maybeStopTrackingJobLocked(jobFg3, null, false);
+ mQuotaController.maybeStopTrackingJobLocked(jobFg3, null);
}
advanceElapsedClock(10 * SECOND_IN_MILLIS);
synchronized (mQuotaController.mLock) {
- mQuotaController.maybeStopTrackingJobLocked(jobBg2, null, false);
+ mQuotaController.maybeStopTrackingJobLocked(jobBg2, null);
}
assertEquals(expected, mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
@@ -4063,7 +4077,7 @@
}
advanceElapsedClock(10 * SECOND_IN_MILLIS);
synchronized (mQuotaController.mLock) {
- mQuotaController.maybeStopTrackingJobLocked(jobBg1, jobBg1, true);
+ mQuotaController.maybeStopTrackingJobLocked(jobBg1, jobBg1);
}
advanceElapsedClock(10 * SECOND_IN_MILLIS); // UID "inactive" now
start = JobSchedulerService.sElapsedRealtimeClock.millis();
@@ -4073,11 +4087,11 @@
}
advanceElapsedClock(10 * SECOND_IN_MILLIS);
synchronized (mQuotaController.mLock) {
- mQuotaController.maybeStopTrackingJobLocked(jobFg3, null, false);
+ mQuotaController.maybeStopTrackingJobLocked(jobFg3, null);
}
advanceElapsedClock(10 * SECOND_IN_MILLIS);
synchronized (mQuotaController.mLock) {
- mQuotaController.maybeStopTrackingJobLocked(jobBg2, null, false);
+ mQuotaController.maybeStopTrackingJobLocked(jobBg2, null);
}
expected.add(createTimingSession(start, 20 * SECOND_IN_MILLIS, 2));
assertEquals(expected, mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
@@ -4116,11 +4130,11 @@
}
advanceElapsedClock(10 * SECOND_IN_MILLIS);
synchronized (mQuotaController.mLock) {
- mQuotaController.maybeStopTrackingJobLocked(jobFg1, null, false);
+ mQuotaController.maybeStopTrackingJobLocked(jobFg1, null);
}
advanceElapsedClock(10 * SECOND_IN_MILLIS);
synchronized (mQuotaController.mLock) {
- mQuotaController.maybeStopTrackingJobLocked(jobFg2, null, false);
+ mQuotaController.maybeStopTrackingJobLocked(jobFg2, null);
}
assertNull(mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
@@ -4155,11 +4169,11 @@
}
advanceElapsedClock(10 * SECOND_IN_MILLIS);
synchronized (mQuotaController.mLock) {
- mQuotaController.maybeStopTrackingJobLocked(jobBg1, null, false);
+ mQuotaController.maybeStopTrackingJobLocked(jobBg1, null);
}
advanceElapsedClock(10 * SECOND_IN_MILLIS);
synchronized (mQuotaController.mLock) {
- mQuotaController.maybeStopTrackingJobLocked(jobBg2, null, false);
+ mQuotaController.maybeStopTrackingJobLocked(jobBg2, null);
}
assertEquals(2, stats.jobCountInRateLimitingWindow);
@@ -4193,7 +4207,7 @@
}
advanceElapsedClock(10 * SECOND_IN_MILLIS);
synchronized (mQuotaController.mLock) {
- mQuotaController.maybeStopTrackingJobLocked(jobBg1, jobBg1, true);
+ mQuotaController.maybeStopTrackingJobLocked(jobBg1, jobBg1);
}
expected.add(createTimingSession(start, 10 * SECOND_IN_MILLIS, 1));
assertEquals(expected, mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
@@ -4218,11 +4232,11 @@
}
advanceElapsedClock(10 * SECOND_IN_MILLIS);
synchronized (mQuotaController.mLock) {
- mQuotaController.maybeStopTrackingJobLocked(jobTop, null, false);
+ mQuotaController.maybeStopTrackingJobLocked(jobTop, null);
}
advanceElapsedClock(10 * SECOND_IN_MILLIS);
synchronized (mQuotaController.mLock) {
- mQuotaController.maybeStopTrackingJobLocked(jobBg2, null, false);
+ mQuotaController.maybeStopTrackingJobLocked(jobBg2, null);
}
assertEquals(expected, mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
@@ -4253,7 +4267,7 @@
}
advanceElapsedClock(10 * SECOND_IN_MILLIS);
synchronized (mQuotaController.mLock) {
- mQuotaController.maybeStopTrackingJobLocked(jobBg1, jobBg1, true);
+ mQuotaController.maybeStopTrackingJobLocked(jobBg1, jobBg1);
}
advanceElapsedClock(5 * SECOND_IN_MILLIS);
setProcessState(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
@@ -4270,12 +4284,12 @@
}
advanceElapsedClock(10 * SECOND_IN_MILLIS);
synchronized (mQuotaController.mLock) {
- mQuotaController.maybeStopTrackingJobLocked(jobTop, null, false);
+ mQuotaController.maybeStopTrackingJobLocked(jobTop, null);
}
advanceElapsedClock(10 * SECOND_IN_MILLIS);
synchronized (mQuotaController.mLock) {
- mQuotaController.maybeStopTrackingJobLocked(jobBg2, null, false);
- mQuotaController.maybeStopTrackingJobLocked(jobFg1, null, false);
+ mQuotaController.maybeStopTrackingJobLocked(jobBg2, null);
+ mQuotaController.maybeStopTrackingJobLocked(jobFg1, null);
}
expected.add(createTimingSession(start, 20 * SECOND_IN_MILLIS, 2));
assertEquals(expected, mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
@@ -4312,7 +4326,7 @@
}
advanceElapsedClock(10 * SECOND_IN_MILLIS);
synchronized (mQuotaController.mLock) {
- mQuotaController.maybeStopTrackingJobLocked(job1, job1, true);
+ mQuotaController.maybeStopTrackingJobLocked(job1, job1);
}
expected.add(createTimingSession(start, 10 * SECOND_IN_MILLIS, 1));
assertEquals(expected,
@@ -4329,7 +4343,7 @@
}
advanceElapsedClock(10 * SECOND_IN_MILLIS);
synchronized (mQuotaController.mLock) {
- mQuotaController.maybeStopTrackingJobLocked(job2, null, false);
+ mQuotaController.maybeStopTrackingJobLocked(job2, null);
}
expected.add(createTimingSession(start, 10 * SECOND_IN_MILLIS, 1));
assertEquals(expected,
@@ -4348,7 +4362,7 @@
long elapsedGracePeriodMs = 2 * SECOND_IN_MILLIS;
advanceElapsedClock(elapsedGracePeriodMs);
synchronized (mQuotaController.mLock) {
- mQuotaController.maybeStopTrackingJobLocked(job3, null, false);
+ mQuotaController.maybeStopTrackingJobLocked(job3, null);
}
expected.add(createTimingSession(start, 10 * SECOND_IN_MILLIS + elapsedGracePeriodMs, 1));
assertEquals(expected,
@@ -4373,7 +4387,7 @@
advanceElapsedClock(10 * SECOND_IN_MILLIS);
expected.add(createTimingSession(start, remainingGracePeriod + 10 * SECOND_IN_MILLIS, 1));
synchronized (mQuotaController.mLock) {
- mQuotaController.maybeStopTrackingJobLocked(job4, job4, true);
+ mQuotaController.maybeStopTrackingJobLocked(job4, job4);
}
assertEquals(expected,
mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
@@ -4387,7 +4401,7 @@
}
advanceElapsedClock(10 * SECOND_IN_MILLIS);
synchronized (mQuotaController.mLock) {
- mQuotaController.maybeStopTrackingJobLocked(job5, job5, true);
+ mQuotaController.maybeStopTrackingJobLocked(job5, job5);
}
expected.add(createTimingSession(start, 10 * SECOND_IN_MILLIS, 1));
assertEquals(expected,
@@ -4611,7 +4625,7 @@
SOURCE_USER_ID, SOURCE_PACKAGE, standbyBucket);
}
verify(mAlarmManager, timeout(1000).times(0)).setWindow(
- anyInt(), anyLong(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any());
+ anyInt(), anyLong(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any(Handler.class));
// Ran jobs up to the job limit. All of them should be allowed to run.
for (int i = 0; i < mQcConstants.MAX_JOB_COUNT_PER_RATE_LIMITING_WINDOW; ++i) {
@@ -4624,13 +4638,13 @@
}
advanceElapsedClock(SECOND_IN_MILLIS);
synchronized (mQuotaController.mLock) {
- mQuotaController.maybeStopTrackingJobLocked(job, null, false);
+ mQuotaController.maybeStopTrackingJobLocked(job, null);
}
advanceElapsedClock(SECOND_IN_MILLIS);
}
// Start alarm shouldn't have been scheduled since the app was in quota up until this point.
verify(mAlarmManager, timeout(1000).times(0)).setWindow(
- anyInt(), anyLong(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any());
+ anyInt(), anyLong(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any(Handler.class));
// The app is now out of job count quota
JobStatus throttledJob = createJobStatus(
@@ -4649,7 +4663,7 @@
final long expectedWorkingAlarmTime = stats.jobRateLimitExpirationTimeElapsed;
verify(mAlarmManager, timeout(1000).times(1)).setWindow(
anyInt(), eq(expectedWorkingAlarmTime), anyLong(),
- eq(TAG_QUOTA_CHECK), any(), any());
+ eq(TAG_QUOTA_CHECK), any(), any(Handler.class));
}
/**
@@ -4680,7 +4694,7 @@
SOURCE_USER_ID, SOURCE_PACKAGE, standbyBucket);
}
verify(mAlarmManager, timeout(1000).times(0)).setWindow(
- anyInt(), anyLong(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any());
+ anyInt(), anyLong(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any(Handler.class));
// Ran jobs up to the job limit. All of them should be allowed to run.
for (int i = 0; i < mQcConstants.MAX_SESSION_COUNT_PER_RATE_LIMITING_WINDOW; ++i) {
@@ -4695,13 +4709,13 @@
}
advanceElapsedClock(SECOND_IN_MILLIS);
synchronized (mQuotaController.mLock) {
- mQuotaController.maybeStopTrackingJobLocked(job, null, false);
+ mQuotaController.maybeStopTrackingJobLocked(job, null);
}
advanceElapsedClock(SECOND_IN_MILLIS);
}
// Start alarm shouldn't have been scheduled since the app was in quota up until this point.
verify(mAlarmManager, timeout(1000).times(0)).setWindow(
- anyInt(), anyLong(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any());
+ anyInt(), anyLong(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any(Handler.class));
// The app is now out of session count quota
JobStatus throttledJob = createJobStatus(
@@ -4721,7 +4735,7 @@
final long expectedWorkingAlarmTime = stats.sessionRateLimitExpirationTimeElapsed;
verify(mAlarmManager, timeout(1000).times(1)).setWindow(
anyInt(), eq(expectedWorkingAlarmTime), anyLong(),
- eq(TAG_QUOTA_CHECK), any(), any());
+ eq(TAG_QUOTA_CHECK), any(), any(Handler.class));
}
@Test
@@ -5185,7 +5199,8 @@
SOURCE_USER_ID, SOURCE_PACKAGE, standbyBucket);
}
inOrder.verify(mAlarmManager, timeout(1000).times(0))
- .setWindow(anyInt(), anyLong(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any());
+ .setWindow(anyInt(), anyLong(), anyLong(), eq(TAG_QUOTA_CHECK), any(),
+ any(Handler.class));
// Test with timing sessions out of window.
final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
@@ -5196,7 +5211,8 @@
SOURCE_USER_ID, SOURCE_PACKAGE, standbyBucket);
}
inOrder.verify(mAlarmManager, timeout(1000).times(0))
- .setWindow(anyInt(), anyLong(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any());
+ .setWindow(anyInt(), anyLong(), anyLong(), eq(TAG_QUOTA_CHECK), any(),
+ any(Handler.class));
// Test with timing sessions in window but still in quota.
final long end = now - (22 * HOUR_IN_MILLIS - 5 * MINUTE_IN_MILLIS);
@@ -5208,7 +5224,8 @@
SOURCE_USER_ID, SOURCE_PACKAGE, standbyBucket);
}
inOrder.verify(mAlarmManager, timeout(1000).times(0))
- .setWindow(anyInt(), anyLong(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any());
+ .setWindow(anyInt(), anyLong(), anyLong(), eq(TAG_QUOTA_CHECK), any(),
+ any(Handler.class));
// Add some more sessions, but still in quota.
mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
@@ -5220,7 +5237,8 @@
SOURCE_USER_ID, SOURCE_PACKAGE, standbyBucket);
}
inOrder.verify(mAlarmManager, timeout(1000).times(0))
- .setWindow(anyInt(), anyLong(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any());
+ .setWindow(anyInt(), anyLong(), anyLong(), eq(TAG_QUOTA_CHECK), any(),
+ any(Handler.class));
// Test when out of quota.
mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
@@ -5230,7 +5248,8 @@
SOURCE_USER_ID, SOURCE_PACKAGE, standbyBucket);
}
inOrder.verify(mAlarmManager, timeout(1000).times(1)).setWindow(
- anyInt(), eq(expectedAlarmTime), anyLong(), eq(TAG_QUOTA_CHECK), any(), any());
+ anyInt(), eq(expectedAlarmTime), anyLong(), eq(TAG_QUOTA_CHECK), any(),
+ any(Handler.class));
// Alarm already scheduled, so make sure it's not scheduled again.
synchronized (mQuotaController.mLock) {
@@ -5238,7 +5257,8 @@
SOURCE_USER_ID, SOURCE_PACKAGE, standbyBucket);
}
inOrder.verify(mAlarmManager, timeout(1000).times(0))
- .setWindow(anyInt(), anyLong(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any());
+ .setWindow(anyInt(), anyLong(), anyLong(), eq(TAG_QUOTA_CHECK), any(),
+ any(Handler.class));
}
/** Tests that the start alarm is properly rescheduled if the app's bucket is changed. */
@@ -5282,7 +5302,8 @@
SOURCE_USER_ID, SOURCE_PACKAGE, ACTIVE_INDEX);
}
inOrder.verify(mAlarmManager, timeout(1000).times(0))
- .setWindow(anyInt(), anyLong(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any());
+ .setWindow(anyInt(), anyLong(), anyLong(), eq(TAG_QUOTA_CHECK), any(),
+ any(Handler.class));
inOrder.verify(mAlarmManager, timeout(1000).times(0))
.cancel(any(AlarmManager.OnAlarmListener.class));
@@ -5297,7 +5318,7 @@
}
inOrder.verify(mAlarmManager, timeout(1000).times(1)).setWindow(
anyInt(), eq(expectedWorkingAlarmTime), anyLong(),
- eq(TAG_QUOTA_CHECK), any(), any());
+ eq(TAG_QUOTA_CHECK), any(), any(Handler.class));
setStandbyBucket(FREQUENT_INDEX);
final long expectedFrequentAlarmTime =
@@ -5308,7 +5329,7 @@
}
inOrder.verify(mAlarmManager, timeout(1000).times(1)).setWindow(
anyInt(), eq(expectedFrequentAlarmTime), anyLong(),
- eq(TAG_QUOTA_CHECK), any(), any());
+ eq(TAG_QUOTA_CHECK), any(), any(Handler.class));
setStandbyBucket(RARE_INDEX);
final long expectedRareAlarmTime =
@@ -5319,7 +5340,8 @@
SOURCE_USER_ID, SOURCE_PACKAGE, RARE_INDEX);
}
inOrder.verify(mAlarmManager, timeout(1000).times(1)).setWindow(
- anyInt(), eq(expectedRareAlarmTime), anyLong(), eq(TAG_QUOTA_CHECK), any(), any());
+ anyInt(), eq(expectedRareAlarmTime), anyLong(), eq(TAG_QUOTA_CHECK), any(),
+ any(Handler.class));
// And back up again.
setStandbyBucket(FREQUENT_INDEX);
@@ -5329,7 +5351,7 @@
}
inOrder.verify(mAlarmManager, timeout(1000).times(1)).setWindow(
anyInt(), eq(expectedFrequentAlarmTime), anyLong(),
- eq(TAG_QUOTA_CHECK), any(), any());
+ eq(TAG_QUOTA_CHECK), any(), any(Handler.class));
setStandbyBucket(WORKING_INDEX);
synchronized (mQuotaController.mLock) {
@@ -5338,7 +5360,7 @@
}
inOrder.verify(mAlarmManager, timeout(1000).times(1)).setWindow(
anyInt(), eq(expectedWorkingAlarmTime), anyLong(),
- eq(TAG_QUOTA_CHECK), any(), any());
+ eq(TAG_QUOTA_CHECK), any(), any(Handler.class));
setStandbyBucket(ACTIVE_INDEX);
synchronized (mQuotaController.mLock) {
@@ -5346,7 +5368,8 @@
SOURCE_USER_ID, SOURCE_PACKAGE, ACTIVE_INDEX);
}
inOrder.verify(mAlarmManager, timeout(1000).times(0))
- .setWindow(anyInt(), anyLong(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any());
+ .setWindow(anyInt(), anyLong(), anyLong(), eq(TAG_QUOTA_CHECK), any(),
+ any(Handler.class));
inOrder.verify(mAlarmManager, timeout(1000).times(1))
.cancel(any(AlarmManager.OnAlarmListener.class));
}
@@ -5388,7 +5411,8 @@
SOURCE_USER_ID, SOURCE_PACKAGE, WORKING_INDEX);
}
verify(mAlarmManager, timeout(1000).times(1)).setWindow(
- anyInt(), eq(expectedAlarmTime), anyLong(), eq(TAG_QUOTA_CHECK), any(), any());
+ anyInt(), eq(expectedAlarmTime), anyLong(), eq(TAG_QUOTA_CHECK), any(),
+ any(Handler.class));
}
/** Tests that TimingSessions aren't saved when the device is charging. */
@@ -5408,7 +5432,7 @@
}
advanceElapsedClock(5 * SECOND_IN_MILLIS);
synchronized (mQuotaController.mLock) {
- mQuotaController.maybeStopTrackingJobLocked(jobStatus, null, false);
+ mQuotaController.maybeStopTrackingJobLocked(jobStatus, null);
}
assertNull(mQuotaController.getEJTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
}
@@ -5434,7 +5458,7 @@
}
advanceElapsedClock(5 * SECOND_IN_MILLIS);
synchronized (mQuotaController.mLock) {
- mQuotaController.maybeStopTrackingJobLocked(jobStatus, null, false);
+ mQuotaController.maybeStopTrackingJobLocked(jobStatus, null);
}
expected.add(createTimingSession(start, 5 * SECOND_IN_MILLIS, 1));
assertEquals(expected,
@@ -5464,7 +5488,7 @@
}
advanceElapsedClock(10 * SECOND_IN_MILLIS);
synchronized (mQuotaController.mLock) {
- mQuotaController.maybeStopTrackingJobLocked(jobStatus, null, false);
+ mQuotaController.maybeStopTrackingJobLocked(jobStatus, null);
}
advanceElapsedClock(10 * SECOND_IN_MILLIS);
synchronized (mQuotaController.mLock) {
@@ -5472,11 +5496,11 @@
}
advanceElapsedClock(20 * SECOND_IN_MILLIS);
synchronized (mQuotaController.mLock) {
- mQuotaController.maybeStopTrackingJobLocked(jobStatus3, null, false);
+ mQuotaController.maybeStopTrackingJobLocked(jobStatus3, null);
}
advanceElapsedClock(10 * SECOND_IN_MILLIS);
synchronized (mQuotaController.mLock) {
- mQuotaController.maybeStopTrackingJobLocked(jobStatus2, null, false);
+ mQuotaController.maybeStopTrackingJobLocked(jobStatus2, null);
}
expected.add(createTimingSession(start, MINUTE_IN_MILLIS, 3));
assertEquals(expected,
@@ -5521,7 +5545,7 @@
long start = JobSchedulerService.sElapsedRealtimeClock.millis();
advanceElapsedClock(10 * SECOND_IN_MILLIS);
synchronized (mQuotaController.mLock) {
- mQuotaController.maybeStopTrackingJobLocked(jobStatus, jobStatus, true);
+ mQuotaController.maybeStopTrackingJobLocked(jobStatus, jobStatus);
}
expected.add(createTimingSession(start, 10 * SECOND_IN_MILLIS, 1));
assertEquals(expected,
@@ -5553,18 +5577,18 @@
}
advanceElapsedClock(10 * SECOND_IN_MILLIS);
synchronized (mQuotaController.mLock) {
- mQuotaController.maybeStopTrackingJobLocked(jobStatus3, null, false);
+ mQuotaController.maybeStopTrackingJobLocked(jobStatus3, null);
}
advanceElapsedClock(10 * SECOND_IN_MILLIS);
synchronized (mQuotaController.mLock) {
- mQuotaController.maybeStopTrackingJobLocked(jobStatus2, null, false);
+ mQuotaController.maybeStopTrackingJobLocked(jobStatus2, null);
}
advanceElapsedClock(10 * SECOND_IN_MILLIS);
setDischarging();
start = JobSchedulerService.sElapsedRealtimeClock.millis();
advanceElapsedClock(20 * SECOND_IN_MILLIS);
synchronized (mQuotaController.mLock) {
- mQuotaController.maybeStopTrackingJobLocked(jobStatus, null, false);
+ mQuotaController.maybeStopTrackingJobLocked(jobStatus, null);
}
expected.add(createTimingSession(start, 20 * SECOND_IN_MILLIS, 1));
assertEquals(expected,
@@ -5583,7 +5607,7 @@
setCharging();
advanceElapsedClock(10 * SECOND_IN_MILLIS);
synchronized (mQuotaController.mLock) {
- mQuotaController.maybeStopTrackingJobLocked(jobStatus2, null, false);
+ mQuotaController.maybeStopTrackingJobLocked(jobStatus2, null);
}
assertEquals(expected,
mQuotaController.getEJTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
@@ -5610,7 +5634,7 @@
}
advanceElapsedClock(5 * SECOND_IN_MILLIS);
synchronized (mQuotaController.mLock) {
- mQuotaController.maybeStopTrackingJobLocked(jobStatus, null, false);
+ mQuotaController.maybeStopTrackingJobLocked(jobStatus, null);
}
expected.add(createTimingSession(start, 5 * SECOND_IN_MILLIS, 1));
assertEquals(expected,
@@ -5640,7 +5664,7 @@
}
advanceElapsedClock(10 * SECOND_IN_MILLIS);
synchronized (mQuotaController.mLock) {
- mQuotaController.maybeStopTrackingJobLocked(jobStatus, null, false);
+ mQuotaController.maybeStopTrackingJobLocked(jobStatus, null);
}
advanceElapsedClock(10 * SECOND_IN_MILLIS);
synchronized (mQuotaController.mLock) {
@@ -5648,11 +5672,11 @@
}
advanceElapsedClock(20 * SECOND_IN_MILLIS);
synchronized (mQuotaController.mLock) {
- mQuotaController.maybeStopTrackingJobLocked(jobStatus3, null, false);
+ mQuotaController.maybeStopTrackingJobLocked(jobStatus3, null);
}
advanceElapsedClock(10 * SECOND_IN_MILLIS);
synchronized (mQuotaController.mLock) {
- mQuotaController.maybeStopTrackingJobLocked(jobStatus2, null, false);
+ mQuotaController.maybeStopTrackingJobLocked(jobStatus2, null);
}
expected.add(createTimingSession(start, MINUTE_IN_MILLIS, 3));
assertEquals(expected,
@@ -5680,7 +5704,7 @@
setProcessState(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
advanceElapsedClock(5 * SECOND_IN_MILLIS);
synchronized (mQuotaController.mLock) {
- mQuotaController.maybeStopTrackingJobLocked(jobStatus, null, false);
+ mQuotaController.maybeStopTrackingJobLocked(jobStatus, null);
}
assertNull(mQuotaController.getEJTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
}
@@ -5715,7 +5739,7 @@
}
advanceElapsedClock(10 * SECOND_IN_MILLIS);
synchronized (mQuotaController.mLock) {
- mQuotaController.maybeStopTrackingJobLocked(jobBg1, jobBg1, true);
+ mQuotaController.maybeStopTrackingJobLocked(jobBg1, jobBg1);
}
expected.add(createTimingSession(start, 10 * SECOND_IN_MILLIS, 1));
assertEquals(expected,
@@ -5741,11 +5765,11 @@
}
advanceElapsedClock(10 * SECOND_IN_MILLIS);
synchronized (mQuotaController.mLock) {
- mQuotaController.maybeStopTrackingJobLocked(jobFg3, null, false);
+ mQuotaController.maybeStopTrackingJobLocked(jobFg3, null);
}
advanceElapsedClock(10 * SECOND_IN_MILLIS);
synchronized (mQuotaController.mLock) {
- mQuotaController.maybeStopTrackingJobLocked(jobBg2, null, false);
+ mQuotaController.maybeStopTrackingJobLocked(jobBg2, null);
}
assertEquals(expected,
mQuotaController.getEJTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
@@ -5775,7 +5799,7 @@
}
advanceElapsedClock(10 * SECOND_IN_MILLIS);
synchronized (mQuotaController.mLock) {
- mQuotaController.maybeStopTrackingJobLocked(jobBg1, jobBg1, true);
+ mQuotaController.maybeStopTrackingJobLocked(jobBg1, jobBg1);
}
advanceElapsedClock(10 * SECOND_IN_MILLIS); // UID "inactive" now
start = JobSchedulerService.sElapsedRealtimeClock.millis();
@@ -5785,11 +5809,11 @@
}
advanceElapsedClock(10 * SECOND_IN_MILLIS);
synchronized (mQuotaController.mLock) {
- mQuotaController.maybeStopTrackingJobLocked(jobFg3, null, false);
+ mQuotaController.maybeStopTrackingJobLocked(jobFg3, null);
}
advanceElapsedClock(10 * SECOND_IN_MILLIS);
synchronized (mQuotaController.mLock) {
- mQuotaController.maybeStopTrackingJobLocked(jobBg2, null, false);
+ mQuotaController.maybeStopTrackingJobLocked(jobBg2, null);
}
expected.add(createTimingSession(start, 20 * SECOND_IN_MILLIS, 2));
assertEquals(expected,
@@ -5825,7 +5849,7 @@
}
advanceElapsedClock(10 * SECOND_IN_MILLIS);
synchronized (mQuotaController.mLock) {
- mQuotaController.maybeStopTrackingJobLocked(jobBg1, jobBg1, true);
+ mQuotaController.maybeStopTrackingJobLocked(jobBg1, jobBg1);
}
expected.add(createTimingSession(start, 10 * SECOND_IN_MILLIS, 1));
assertEquals(expected,
@@ -5851,11 +5875,11 @@
}
advanceElapsedClock(10 * SECOND_IN_MILLIS);
synchronized (mQuotaController.mLock) {
- mQuotaController.maybeStopTrackingJobLocked(jobTop, null, false);
+ mQuotaController.maybeStopTrackingJobLocked(jobTop, null);
}
advanceElapsedClock(10 * SECOND_IN_MILLIS);
synchronized (mQuotaController.mLock) {
- mQuotaController.maybeStopTrackingJobLocked(jobBg2, null, false);
+ mQuotaController.maybeStopTrackingJobLocked(jobBg2, null);
}
assertEquals(expected,
mQuotaController.getEJTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
@@ -5887,7 +5911,7 @@
}
advanceElapsedClock(10 * SECOND_IN_MILLIS);
synchronized (mQuotaController.mLock) {
- mQuotaController.maybeStopTrackingJobLocked(jobBg1, jobBg1, true);
+ mQuotaController.maybeStopTrackingJobLocked(jobBg1, jobBg1);
}
advanceElapsedClock(5 * SECOND_IN_MILLIS);
setProcessState(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
@@ -5904,12 +5928,12 @@
}
advanceElapsedClock(10 * SECOND_IN_MILLIS);
synchronized (mQuotaController.mLock) {
- mQuotaController.maybeStopTrackingJobLocked(jobTop, null, false);
+ mQuotaController.maybeStopTrackingJobLocked(jobTop, null);
}
advanceElapsedClock(10 * SECOND_IN_MILLIS);
synchronized (mQuotaController.mLock) {
- mQuotaController.maybeStopTrackingJobLocked(jobBg2, null, false);
- mQuotaController.maybeStopTrackingJobLocked(jobFg1, null, false);
+ mQuotaController.maybeStopTrackingJobLocked(jobBg2, null);
+ mQuotaController.maybeStopTrackingJobLocked(jobFg1, null);
}
expected.add(createTimingSession(start, 20 * SECOND_IN_MILLIS, 2));
assertEquals(expected,
@@ -5946,7 +5970,7 @@
}
advanceElapsedClock(10 * SECOND_IN_MILLIS);
synchronized (mQuotaController.mLock) {
- mQuotaController.maybeStopTrackingJobLocked(job1, job1, true);
+ mQuotaController.maybeStopTrackingJobLocked(job1, job1);
}
expected.add(createTimingSession(start, 10 * SECOND_IN_MILLIS, 1));
assertEquals(expected,
@@ -5963,7 +5987,7 @@
}
advanceElapsedClock(10 * SECOND_IN_MILLIS);
synchronized (mQuotaController.mLock) {
- mQuotaController.maybeStopTrackingJobLocked(job2, null, false);
+ mQuotaController.maybeStopTrackingJobLocked(job2, null);
}
assertEquals(expected,
mQuotaController.getEJTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
@@ -5981,7 +6005,7 @@
long elapsedGracePeriodMs = 2 * SECOND_IN_MILLIS;
advanceElapsedClock(elapsedGracePeriodMs);
synchronized (mQuotaController.mLock) {
- mQuotaController.maybeStopTrackingJobLocked(job3, null, false);
+ mQuotaController.maybeStopTrackingJobLocked(job3, null);
}
assertEquals(expected,
mQuotaController.getEJTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
@@ -6005,7 +6029,7 @@
advanceElapsedClock(10 * SECOND_IN_MILLIS);
expected.add(createTimingSession(start, 10 * SECOND_IN_MILLIS, 1));
synchronized (mQuotaController.mLock) {
- mQuotaController.maybeStopTrackingJobLocked(job4, job4, true);
+ mQuotaController.maybeStopTrackingJobLocked(job4, job4);
}
assertEquals(expected,
mQuotaController.getEJTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
@@ -6019,7 +6043,7 @@
}
advanceElapsedClock(10 * SECOND_IN_MILLIS);
synchronized (mQuotaController.mLock) {
- mQuotaController.maybeStopTrackingJobLocked(job5, job5, true);
+ mQuotaController.maybeStopTrackingJobLocked(job5, job5);
}
expected.add(createTimingSession(start, 10 * SECOND_IN_MILLIS, 1));
assertEquals(expected,
@@ -6049,7 +6073,7 @@
}
advanceElapsedClock(10 * SECOND_IN_MILLIS);
synchronized (mQuotaController.mLock) {
- mQuotaController.maybeStopTrackingJobLocked(job, job, true);
+ mQuotaController.maybeStopTrackingJobLocked(job, job);
}
expected.add(createTimingSession(start, 10 * SECOND_IN_MILLIS, 1));
assertEquals(expected,
@@ -6066,7 +6090,7 @@
}
advanceElapsedClock(10 * SECOND_IN_MILLIS);
synchronized (mQuotaController.mLock) {
- mQuotaController.maybeStopTrackingJobLocked(job, null, false);
+ mQuotaController.maybeStopTrackingJobLocked(job, null);
}
expected.add(createTimingSession(start, 10 * SECOND_IN_MILLIS, 1));
assertEquals(expected,
@@ -6085,7 +6109,7 @@
long elapsedGracePeriodMs = 2 * SECOND_IN_MILLIS;
advanceElapsedClock(elapsedGracePeriodMs);
synchronized (mQuotaController.mLock) {
- mQuotaController.maybeStopTrackingJobLocked(job, null, false);
+ mQuotaController.maybeStopTrackingJobLocked(job, null);
}
expected.add(createTimingSession(start, 12 * SECOND_IN_MILLIS, 1));
assertEquals(expected,
@@ -6110,7 +6134,7 @@
advanceElapsedClock(10 * SECOND_IN_MILLIS);
expected.add(createTimingSession(start, 10 * SECOND_IN_MILLIS + remainingGracePeriod, 1));
synchronized (mQuotaController.mLock) {
- mQuotaController.maybeStopTrackingJobLocked(job, job, true);
+ mQuotaController.maybeStopTrackingJobLocked(job, job);
}
assertEquals(expected,
mQuotaController.getEJTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
@@ -6124,7 +6148,7 @@
}
advanceElapsedClock(10 * SECOND_IN_MILLIS);
synchronized (mQuotaController.mLock) {
- mQuotaController.maybeStopTrackingJobLocked(job, job, true);
+ mQuotaController.maybeStopTrackingJobLocked(job, job);
}
expected.add(createTimingSession(start, 10 * SECOND_IN_MILLIS, 1));
assertEquals(expected,
@@ -6169,7 +6193,7 @@
// Wait for the grace period to expire so the handler can process the message.
Thread.sleep(gracePeriodMs);
synchronized (mQuotaController.mLock) {
- mQuotaController.maybeStopTrackingJobLocked(job1, job1, true);
+ mQuotaController.maybeStopTrackingJobLocked(job1, job1);
}
assertNull(mQuotaController.getEJTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
@@ -6189,7 +6213,7 @@
// Wait for the grace period to expire so the handler can process the message.
Thread.sleep(gracePeriodMs);
synchronized (mQuotaController.mLock) {
- mQuotaController.maybeStopTrackingJobLocked(job2, null, false);
+ mQuotaController.maybeStopTrackingJobLocked(job2, null);
}
assertNull(mQuotaController.getEJTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE));
@@ -6215,7 +6239,7 @@
Thread.sleep(2 * gracePeriodMs);
advanceElapsedClock(gracePeriodMs);
synchronized (mQuotaController.mLock) {
- mQuotaController.maybeStopTrackingJobLocked(job3, job3, true);
+ mQuotaController.maybeStopTrackingJobLocked(job3, job3);
}
expected.add(createTimingSession(start, gracePeriodMs, 1));
assertEquals(expected,
@@ -6243,7 +6267,7 @@
Thread.sleep(2 * gracePeriodMs);
advanceElapsedClock(gracePeriodMs);
synchronized (mQuotaController.mLock) {
- mQuotaController.maybeStopTrackingJobLocked(job4, job4, true);
+ mQuotaController.maybeStopTrackingJobLocked(job4, job4);
}
expected.add(createTimingSession(start, gracePeriodMs, 1));
assertEquals(expected,
@@ -6270,7 +6294,7 @@
Thread.sleep(2 * gracePeriodMs);
advanceElapsedClock(10 * SECOND_IN_MILLIS);
synchronized (mQuotaController.mLock) {
- mQuotaController.maybeStopTrackingJobLocked(job5, job5, true);
+ mQuotaController.maybeStopTrackingJobLocked(job5, job5);
}
expected.add(createTimingSession(start, 10 * SECOND_IN_MILLIS, 1));
assertEquals(expected,
@@ -6424,7 +6448,7 @@
}
advanceElapsedClock(10 * SECOND_IN_MILLIS);
synchronized (mQuotaController.mLock) {
- mQuotaController.maybeStopTrackingJobLocked(jobReg1, jobReg1, true);
+ mQuotaController.maybeStopTrackingJobLocked(jobReg1, jobReg1);
}
expectedRegular.add(createTimingSession(start, 10 * SECOND_IN_MILLIS, 1));
assertEquals(expectedRegular,
@@ -6440,7 +6464,7 @@
}
advanceElapsedClock(10 * SECOND_IN_MILLIS);
synchronized (mQuotaController.mLock) {
- mQuotaController.maybeStopTrackingJobLocked(jobEJ1, null, false);
+ mQuotaController.maybeStopTrackingJobLocked(jobEJ1, null);
}
expectedEJ.add(createTimingSession(start, 10 * SECOND_IN_MILLIS, 1));
assertEquals(expectedRegular,
@@ -6461,12 +6485,12 @@
}
advanceElapsedClock(5 * SECOND_IN_MILLIS);
synchronized (mQuotaController.mLock) {
- mQuotaController.maybeStopTrackingJobLocked(jobEJ2, null, false);
+ mQuotaController.maybeStopTrackingJobLocked(jobEJ2, null);
}
expectedEJ.add(createTimingSession(start, 10 * SECOND_IN_MILLIS, 1));
advanceElapsedClock(5 * SECOND_IN_MILLIS);
synchronized (mQuotaController.mLock) {
- mQuotaController.maybeStopTrackingJobLocked(jobReg2, null, false);
+ mQuotaController.maybeStopTrackingJobLocked(jobReg2, null);
}
expectedRegular.add(
createTimingSession(start + 5 * SECOND_IN_MILLIS, 10 * SECOND_IN_MILLIS, 1));
@@ -6556,7 +6580,7 @@
}
advanceElapsedClock(5000);
synchronized (mQuotaController.mLock) {
- mQuotaController.maybeStopTrackingJobLocked(regJob, null, false);
+ mQuotaController.maybeStopTrackingJobLocked(regJob, null);
}
assertEquals(0, debit.getTallyLocked());
assertEquals(10 * MINUTE_IN_MILLIS,
@@ -6570,7 +6594,7 @@
}
advanceElapsedClock(5 * MINUTE_IN_MILLIS);
synchronized (mQuotaController.mLock) {
- mQuotaController.maybeStopTrackingJobLocked(eJob, null, false);
+ mQuotaController.maybeStopTrackingJobLocked(eJob, null);
}
assertEquals(5 * MINUTE_IN_MILLIS, debit.getTallyLocked());
assertEquals(5 * MINUTE_IN_MILLIS,
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/StateControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/StateControllerTest.java
index 612e906..51d641b 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/StateControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/StateControllerTest.java
@@ -81,8 +81,7 @@
public void maybeStartTrackingJobLocked(JobStatus jobStatus, JobStatus lastJob) {
}
- public void maybeStopTrackingJobLocked(JobStatus jobStatus, JobStatus incomingJob,
- boolean forUpdate) {
+ public void maybeStopTrackingJobLocked(JobStatus jobStatus, JobStatus incomingJob) {
}
public void dumpControllerStateLocked(IndentingPrintWriter pw,
diff --git a/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/ApexManagerTest.java
similarity index 64%
rename from services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java
rename to services/tests/mockingservicestests/src/com/android/server/pm/ApexManagerTest.java
index a7739ed..aabec22 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/ApexManagerTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -31,25 +31,29 @@
import static org.mockito.Mockito.when;
import static org.testng.Assert.assertThrows;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.apex.ApexInfo;
import android.apex.ApexSessionInfo;
import android.apex.ApexSessionParams;
import android.apex.IApexService;
-import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.os.Build;
import android.os.Environment;
import android.os.RemoteException;
import android.os.ServiceSpecificException;
import android.platform.test.annotations.Presubmit;
import androidx.test.filters.SmallTest;
-import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
import com.android.server.pm.parsing.PackageParser2;
-import com.android.server.pm.parsing.TestPackageParser2;
import com.android.server.pm.pkg.AndroidPackage;
+import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -60,88 +64,139 @@
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
+import java.util.Objects;
@SmallTest
@Presubmit
@RunWith(AndroidJUnit4.class)
public class ApexManagerTest {
+
+ @Rule
+ public final MockSystemRule mMockSystem = new MockSystemRule();
+
private static final String TEST_APEX_PKG = "com.android.apex.test";
private static final String TEST_APEX_FILE_NAME = "apex.test.apex";
private static final int TEST_SESSION_ID = 99999999;
private static final int[] TEST_CHILD_SESSION_ID = {8888, 7777};
private ApexManager mApexManager;
- private Context mContext;
private PackageParser2 mPackageParser2;
private IApexService mApexService = mock(IApexService.class);
+ private PackageManagerService mPmService;
+
+ private InstallPackageHelper mInstallPackageHelper;
+
@Before
- public void setUp() throws RemoteException {
- mContext = InstrumentationRegistry.getInstrumentation().getContext();
+ public void setUp() throws Exception {
ApexManager.ApexManagerImpl managerImpl = spy(new ApexManager.ApexManagerImpl());
doReturn(mApexService).when(managerImpl).waitForApexService();
+ when(mApexService.getActivePackages()).thenReturn(new ApexInfo[0]);
mApexManager = managerImpl;
- mPackageParser2 = new TestPackageParser2();
+ mPackageParser2 = new PackageParser2(null, null, null, new PackageParser2.Callback() {
+ @Override
+ public boolean isChangeEnabled(long changeId, @NonNull ApplicationInfo appInfo) {
+ return true;
+ }
+
+ @Override
+ public boolean hasFeature(String feature) {
+ return true;
+ }
+ });
+
+ mMockSystem.system().stageNominalSystemState();
+ mPmService = new PackageManagerService(mMockSystem.mocks().getInjector(),
+ false /*factoryTest*/,
+ MockSystem.Companion.getDEFAULT_VERSION_INFO().fingerprint,
+ false /*isEngBuild*/,
+ false /*isUserDebugBuild*/,
+ Build.VERSION_CODES.CUR_DEVELOPMENT,
+ Build.VERSION.INCREMENTAL);
+ mMockSystem.system().validateFinalState();
+ mInstallPackageHelper = new InstallPackageHelper(mPmService, mock(AppDataHelper.class));
+ }
+
+ @NonNull
+ private List<ApexManager.ScanResult> scanApexInfos(ApexInfo[] apexInfos) {
+ return mInstallPackageHelper.scanApexPackages(apexInfos,
+ ParsingPackageUtils.PARSE_IS_SYSTEM_DIR,
+ PackageManagerService.SCAN_AS_SYSTEM, mPackageParser2,
+ ParallelPackageParser.makeExecutorService());
+ }
+
+ @Nullable
+ private ApexManager.ScanResult findActive(@NonNull List<ApexManager.ScanResult> results) {
+ return results.stream()
+ .filter(it -> it.apexInfo.isActive)
+ .filter(it -> Objects.equals(it.packageName, TEST_APEX_PKG))
+ .findFirst()
+ .orElse(null);
+ }
+
+ @Nullable
+ private ApexManager.ScanResult findFactory(@NonNull List<ApexManager.ScanResult> results,
+ @NonNull String packageName) {
+ return results.stream()
+ .filter(it -> it.apexInfo.isFactory)
+ .filter(it -> Objects.equals(it.packageName, packageName))
+ .findFirst()
+ .orElse(null);
+ }
+
+ @NonNull
+ private AndroidPackage mockParsePackage(@NonNull PackageParser2 parser,
+ @NonNull ApexInfo apexInfo) {
+ var flags = PackageManager.GET_META_DATA | PackageManager.GET_SIGNING_CERTIFICATES;
+ try {
+ var parsedPackage = parser.parsePackage(new File(apexInfo.modulePath), flags,
+ /* useCaches= */ false);
+ ScanPackageUtils.applyPolicy(parsedPackage,
+ PackageManagerService.SCAN_AS_APEX | PackageManagerService.SCAN_AS_SYSTEM,
+ mPmService.getPlatformPackage(), /* isUpdatedSystemApp */ false);
+ // isUpdatedSystemApp is ignoreable above, only used for shared library adjustment
+ return parsedPackage.hideAsFinal();
+ } catch (PackageManagerException e) {
+ throw new RuntimeException(e);
+ }
}
@Test
- public void testGetPackageInfo_setFlagsMatchActivePackage() throws RemoteException {
- ApexInfo[] apexInfo = createApexInfoForTestPkg(true, false);
- ApexPackageInfo apexPackageInfo = new ApexPackageInfo();
- apexPackageInfo.scanApexPackages(
- apexInfo, mPackageParser2, ParallelPackageParser.makeExecutorService());
- final var activePair = apexPackageInfo.getPackageInfo(TEST_APEX_PKG,
- ApexManager.MATCH_ACTIVE_PACKAGE);
+ public void testScanActivePackage() {
+ var apexInfos = createApexInfoForTestPkg(true, false);
+ var results = scanApexInfos(apexInfos);
+ var active = findActive(results);
+ var factory = findFactory(results, TEST_APEX_PKG);
- assertThat(activePair).isNotNull();
- assertThat(activePair.second.getPackageName()).contains(TEST_APEX_PKG);
+ assertThat(active).isNotNull();
+ assertThat(active.packageName).isEqualTo(TEST_APEX_PKG);
- final var factoryPair = apexPackageInfo.getPackageInfo(TEST_APEX_PKG,
- ApexManager.MATCH_FACTORY_PACKAGE);
-
- assertThat(factoryPair).isNull();
+ assertThat(factory).isNull();
}
@Test
- public void testGetPackageInfo_setFlagsMatchFactoryPackage() throws RemoteException {
- ApexInfo[] apexInfo = createApexInfoForTestPkg(false, true);
- ApexPackageInfo apexPackageInfo = new ApexPackageInfo();
- apexPackageInfo.scanApexPackages(
- apexInfo, mPackageParser2, ParallelPackageParser.makeExecutorService());
- var factoryPair = apexPackageInfo.getPackageInfo(TEST_APEX_PKG,
- ApexManager.MATCH_FACTORY_PACKAGE);
+ public void testScanFactoryPackage() {
+ var apexInfos = createApexInfoForTestPkg(false, true);
+ var results = scanApexInfos(apexInfos);
+ var active = findActive(results);
+ var factory = findFactory(results, TEST_APEX_PKG);
- assertThat(factoryPair).isNotNull();
- assertThat(factoryPair.second.getPackageName()).contains(TEST_APEX_PKG);
+ assertThat(factory).isNotNull();
+ assertThat(factory.packageName).contains(TEST_APEX_PKG);
- final var activePair = apexPackageInfo.getPackageInfo(TEST_APEX_PKG,
- ApexManager.MATCH_ACTIVE_PACKAGE);
-
- assertThat(activePair).isNull();
+ assertThat(active).isNull();
}
@Test
- public void testGetPackageInfo_setFlagsNone() throws RemoteException {
- ApexInfo[] apexInfo = createApexInfoForTestPkg(false, true);
- ApexPackageInfo apexPackageInfo = new ApexPackageInfo();
- apexPackageInfo.scanApexPackages(
- apexInfo, mPackageParser2, ParallelPackageParser.makeExecutorService());
-
- assertThat(apexPackageInfo.getPackageInfo(TEST_APEX_PKG, 0)).isNull();
- }
-
- @Test
- public void testGetApexSystemServices() throws RemoteException {
- ApexInfo[] apexInfo = new ApexInfo[] {
+ public void testGetApexSystemServices() {
+ ApexInfo[] apexInfo = new ApexInfo[]{
createApexInfoForTestPkg(false, true, 1),
// only active apex reports apex-system-service
createApexInfoForTestPkg(true, false, 2),
};
- ApexPackageInfo apexPackageInfo = new ApexPackageInfo();
- List<ApexManager.ScanResult> scanResults = apexPackageInfo.scanApexPackages(
- apexInfo, mPackageParser2, ParallelPackageParser.makeExecutorService());
+ List<ApexManager.ScanResult> scanResults = scanApexInfos(apexInfo);
mApexManager.notifyScanResult(scanResults);
List<ApexSystemServiceInfo> services = mApexManager.getApexSystemServices();
@@ -151,73 +206,11 @@
}
@Test
- public void testGetActivePackages() throws RemoteException {
- ApexInfo[] apexInfo = createApexInfoForTestPkg(true, true);
- ApexPackageInfo apexPackageInfo = new ApexPackageInfo();
- apexPackageInfo.scanApexPackages(
- apexInfo, mPackageParser2, ParallelPackageParser.makeExecutorService());
-
- assertThat(apexPackageInfo.getActivePackages()).isNotEmpty();
- }
-
- @Test
- public void testGetActivePackages_noneActivePackages() throws RemoteException {
- ApexInfo[] apexInfo = createApexInfoForTestPkg(false, true);
- ApexPackageInfo apexPackageInfo = new ApexPackageInfo();
- apexPackageInfo.scanApexPackages(
- apexInfo, mPackageParser2, ParallelPackageParser.makeExecutorService());
-
- assertThat(apexPackageInfo.getActivePackages()).isEmpty();
- }
-
- @Test
- public void testGetFactoryPackages() throws RemoteException {
- ApexInfo [] apexInfo = createApexInfoForTestPkg(false, true);
- ApexPackageInfo apexPackageInfo = new ApexPackageInfo();
- apexPackageInfo.scanApexPackages(
- apexInfo, mPackageParser2, ParallelPackageParser.makeExecutorService());
-
- assertThat(apexPackageInfo.getFactoryPackages()).isNotEmpty();
- }
-
- @Test
- public void testGetFactoryPackages_noneFactoryPackages() throws RemoteException {
- ApexInfo[] apexInfo = createApexInfoForTestPkg(true, false);
- ApexPackageInfo apexPackageInfo = new ApexPackageInfo();
- apexPackageInfo.scanApexPackages(
- apexInfo, mPackageParser2, ParallelPackageParser.makeExecutorService());
-
- assertThat(apexPackageInfo.getFactoryPackages()).isEmpty();
- }
-
- @Test
- public void testGetInactivePackages() throws RemoteException {
- ApexInfo[] apexInfo = createApexInfoForTestPkg(false, true);
- ApexPackageInfo apexPackageInfo = new ApexPackageInfo();
- apexPackageInfo.scanApexPackages(
- apexInfo, mPackageParser2, ParallelPackageParser.makeExecutorService());
-
- assertThat(apexPackageInfo.getInactivePackages()).isNotEmpty();
- }
-
- @Test
- public void testGetInactivePackages_noneInactivePackages() throws RemoteException {
- ApexInfo[] apexInfo = createApexInfoForTestPkg(true, false);
- ApexPackageInfo apexPackageInfo = new ApexPackageInfo();
- apexPackageInfo.scanApexPackages(
- apexInfo, mPackageParser2, ParallelPackageParser.makeExecutorService());
-
- assertThat(apexPackageInfo.getInactivePackages()).isEmpty();
- }
-
- @Test
- public void testIsApexPackage() throws RemoteException {
- ApexInfo[] apexInfo = createApexInfoForTestPkg(false, true);
- ApexPackageInfo apexPackageInfo = new ApexPackageInfo();
- apexPackageInfo.scanApexPackages(
- apexInfo, mPackageParser2, ParallelPackageParser.makeExecutorService());
-
- assertThat(apexPackageInfo.isApexPackage(TEST_APEX_PKG)).isTrue();
+ public void testIsApexPackage() {
+ var apexInfos = createApexInfoForTestPkg(false, true);
+ var results = scanApexInfos(apexInfos);
+ var factory = findFactory(results, TEST_APEX_PKG);
+ assertThat(factory.pkg.isApex()).isTrue();
}
@Test
@@ -328,16 +321,14 @@
assertThat(activeApex.apexModuleName).isEqualTo(TEST_APEX_PKG);
ApexInfo[] apexInfo = createApexInfoForTestPkg(true, true);
- ApexPackageInfo apexPackageInfo = new ApexPackageInfo();
- List<ApexManager.ScanResult> scanResults = apexPackageInfo.scanApexPackages(
- apexInfo, mPackageParser2, ParallelPackageParser.makeExecutorService());
+ List<ApexManager.ScanResult> scanResults = scanApexInfos(apexInfo);
mApexManager.notifyScanResult(scanResults);
assertThat(mApexManager.getApkInApexInstallError(activeApex.apexModuleName)).isNull();
mApexManager.reportErrorWithApkInApex(activeApex.apexDirectory.getAbsolutePath(),
"Some random error");
assertThat(mApexManager.getApkInApexInstallError(activeApex.apexModuleName))
- .isEqualTo("Some random error");
+ .isEqualTo("Some random error");
}
/**
@@ -357,9 +348,7 @@
when(fakeApkInApex.getPackageName()).thenReturn("randomPackageName");
ApexInfo[] apexInfo = createApexInfoForTestPkg(true, true);
- ApexPackageInfo apexPackageInfo = new ApexPackageInfo();
- List<ApexManager.ScanResult> scanResults = apexPackageInfo.scanApexPackages(
- apexInfo, mPackageParser2, ParallelPackageParser.makeExecutorService());
+ List<ApexManager.ScanResult> scanResults = scanApexInfos(apexInfo);
mApexManager.notifyScanResult(scanResults);
assertThat(mApexManager.getApksInApex(activeApex.apexModuleName)).isEmpty();
@@ -371,11 +360,9 @@
public void testInstallPackage_activeOnSystem() throws Exception {
ApexInfo activeApexInfo = createApexInfo("test.apex_rebootless", 1, /* isActive= */ true,
/* isFactory= */ true, extractResource("test.apex_rebootless_v1",
- "test.rebootless_apex_v1.apex"));
+ "test.rebootless_apex_v1.apex"));
ApexInfo[] apexInfo = new ApexInfo[]{activeApexInfo};
- ApexPackageInfo apexPackageInfo = new ApexPackageInfo();
- apexPackageInfo.scanApexPackages(
- apexInfo, mPackageParser2, ParallelPackageParser.makeExecutorService());
+ var results = scanApexInfos(apexInfo);
File finalApex = extractResource("test.rebootles_apex_v2", "test.rebootless_apex_v2.apex");
ApexInfo newApexInfo = createApexInfo("test.apex_rebootless", 2, /* isActive= */ true,
@@ -384,32 +371,28 @@
File installedApex = extractResource("installed", "test.rebootless_apex_v2.apex");
newApexInfo = mApexManager.installPackage(installedApex);
- apexPackageInfo.notifyPackageInstalled(newApexInfo, mPackageParser2);
- var newInfo = apexPackageInfo.getPackageInfo("test.apex.rebootless",
- ApexManager.MATCH_ACTIVE_PACKAGE);
- assertThat(newInfo.second.getBaseApkPath()).isEqualTo(finalApex.getAbsolutePath());
- assertThat(newInfo.second.getLongVersionCode()).isEqualTo(2);
+ var newPkg = mockParsePackage(mPackageParser2, newApexInfo);
+ assertThat(newPkg.getBaseApkPath()).isEqualTo(finalApex.getAbsolutePath());
+ assertThat(newPkg.getLongVersionCode()).isEqualTo(2);
- var factoryInfo = apexPackageInfo.getPackageInfo("test.apex.rebootless",
- ApexManager.MATCH_FACTORY_PACKAGE);
- assertThat(factoryInfo.second.getBaseApkPath()).isEqualTo(activeApexInfo.modulePath);
- assertThat(factoryInfo.second.getLongVersionCode()).isEqualTo(1);
- assertThat(factoryInfo.second.isSystem()).isTrue();
+ var factoryPkg = mockParsePackage(mPackageParser2,
+ findFactory(results, "test.apex.rebootless").apexInfo);
+ assertThat(factoryPkg.getBaseApkPath()).isEqualTo(activeApexInfo.modulePath);
+ assertThat(factoryPkg.getLongVersionCode()).isEqualTo(1);
+ assertThat(factoryPkg.isSystem()).isTrue();
}
@Test
public void testInstallPackage_activeOnData() throws Exception {
ApexInfo factoryApexInfo = createApexInfo("test.apex_rebootless", 1, /* isActive= */ false,
/* isFactory= */ true, extractResource("test.apex_rebootless_v1",
- "test.rebootless_apex_v1.apex"));
+ "test.rebootless_apex_v1.apex"));
ApexInfo activeApexInfo = createApexInfo("test.apex_rebootless", 1, /* isActive= */ true,
/* isFactory= */ false, extractResource("test.apex.rebootless@1",
- "test.rebootless_apex_v1.apex"));
+ "test.rebootless_apex_v1.apex"));
ApexInfo[] apexInfo = new ApexInfo[]{factoryApexInfo, activeApexInfo};
- ApexPackageInfo apexPackageInfo = new ApexPackageInfo();
- apexPackageInfo.scanApexPackages(
- apexInfo, mPackageParser2, ParallelPackageParser.makeExecutorService());
+ var results = scanApexInfos(apexInfo);
File finalApex = extractResource("test.rebootles_apex_v2", "test.rebootless_apex_v2.apex");
ApexInfo newApexInfo = createApexInfo("test.apex_rebootless", 2, /* isActive= */ true,
@@ -418,30 +401,20 @@
File installedApex = extractResource("installed", "test.rebootless_apex_v2.apex");
newApexInfo = mApexManager.installPackage(installedApex);
- apexPackageInfo.notifyPackageInstalled(newApexInfo, mPackageParser2);
- var newInfo = apexPackageInfo.getPackageInfo("test.apex.rebootless",
- ApexManager.MATCH_ACTIVE_PACKAGE);
- assertThat(newInfo.second.getBaseApkPath()).isEqualTo(finalApex.getAbsolutePath());
- assertThat(newInfo.second.getLongVersionCode()).isEqualTo(2);
+ var newPkg = mockParsePackage(mPackageParser2, newApexInfo);
+ assertThat(newPkg.getBaseApkPath()).isEqualTo(finalApex.getAbsolutePath());
+ assertThat(newPkg.getLongVersionCode()).isEqualTo(2);
- var factoryInfo = apexPackageInfo.getPackageInfo("test.apex.rebootless",
- ApexManager.MATCH_FACTORY_PACKAGE);
- assertThat(factoryInfo.second.getBaseApkPath()).isEqualTo(factoryApexInfo.modulePath);
- assertThat(factoryInfo.second.getLongVersionCode()).isEqualTo(1);
- assertThat(factoryInfo.second.isSystem()).isTrue();
+ var factoryPkg = mockParsePackage(mPackageParser2,
+ findFactory(results, "test.apex.rebootless").apexInfo);
+ assertThat(factoryPkg.getBaseApkPath()).isEqualTo(factoryApexInfo.modulePath);
+ assertThat(factoryPkg.getLongVersionCode()).isEqualTo(1);
+ assertThat(factoryPkg.isSystem()).isTrue();
}
@Test
public void testInstallPackageBinderCallFails() throws Exception {
- ApexInfo activeApexInfo = createApexInfo("test.apex_rebootless", 1, /* isActive= */ true,
- /* isFactory= */ false, extractResource("test.apex_rebootless_v1",
- "test.rebootless_apex_v1.apex"));
- ApexInfo[] apexInfo = new ApexInfo[]{activeApexInfo};
- ApexPackageInfo apexPackageInfo = new ApexPackageInfo();
- apexPackageInfo.scanApexPackages(
- apexInfo, mPackageParser2, ParallelPackageParser.makeExecutorService());
-
when(mApexService.installAndActivatePackage(anyString())).thenThrow(
new RuntimeException("install failed :("));
@@ -452,14 +425,12 @@
}
@Test
- public void testGetActivePackageNameForApexModuleName() throws Exception {
+ public void testGetActivePackageNameForApexModuleName() {
final String moduleName = "com.android.module_name";
ApexInfo[] apexInfo = createApexInfoForTestPkg(true, false);
apexInfo[0].moduleName = moduleName;
- ApexPackageInfo apexPackageInfo = new ApexPackageInfo();
- List<ApexManager.ScanResult> scanResults = apexPackageInfo.scanApexPackages(
- apexInfo, mPackageParser2, ParallelPackageParser.makeExecutorService());
+ List<ApexManager.ScanResult> scanResults = scanApexInfos(apexInfo);
mApexManager.notifyScanResult(scanResults);
assertThat(mApexManager.getActivePackageNameForApexModuleName(moduleName))
@@ -472,12 +443,13 @@
when(mApexService.getActivePackages()).thenReturn(new ApexInfo[]{apex});
final File backingApexFile = mApexManager.getBackingApexFile(
- new File("/apex/" + TEST_APEX_PKG + "/apk/App/App.apk"));
+ new File(mMockSystem.system().getApexDirectory(),
+ TEST_APEX_PKG + "/apk/App/App.apk"));
assertThat(backingApexFile.getAbsolutePath()).isEqualTo(apex.modulePath);
}
@Test
- public void testGetBackingApexFile_fileNotOnApexMountPoint_returnsNull() throws Exception {
+ public void testGetBackingApexFile_fileNotOnApexMountPoint_returnsNull() {
File result = mApexManager.getBackingApexFile(
new File("/data/local/tmp/whatever/does-not-matter"));
assertThat(result).isNull();
@@ -489,22 +461,23 @@
when(mApexService.getActivePackages()).thenReturn(new ApexInfo[]{apex});
final File backingApexFile = mApexManager.getBackingApexFile(
- new File("/apex/com.wrong.apex/apk/App"));
+ new File(mMockSystem.system().getApexDirectory(), "com.wrong.apex/apk/App"));
assertThat(backingApexFile).isNull();
}
@Test
- public void testGetBackingApexFiles_topLevelApexDir_returnsNull() throws Exception {
+ public void testGetBackingApexFiles_topLevelApexDir_returnsNull() {
assertThat(mApexManager.getBackingApexFile(Environment.getApexDirectory())).isNull();
assertThat(mApexManager.getBackingApexFile(new File("/apex/"))).isNull();
assertThat(mApexManager.getBackingApexFile(new File("/apex//"))).isNull();
}
@Test
- public void testGetBackingApexFiles_flattenedApex() throws Exception {
+ public void testGetBackingApexFiles_flattenedApex() {
ApexManager flattenedApexManager = new ApexManager.ApexManagerFlattenedApex();
final File backingApexFile = flattenedApexManager.getBackingApexFile(
- new File("/apex/com.android.apex.cts.shim/app/CtsShim/CtsShim.apk"));
+ new File(mMockSystem.system().getApexDirectory(),
+ "com.android.apex.cts.shim/app/CtsShim/CtsShim.apk"));
assertThat(backingApexFile).isNull();
}
@@ -521,7 +494,7 @@
}
private ApexInfo createApexInfoForTestPkg(boolean isActive, boolean isFactory, int version) {
- File apexFile = extractResource(TEST_APEX_PKG, TEST_APEX_FILE_NAME);
+ File apexFile = extractResource(TEST_APEX_PKG, TEST_APEX_FILE_NAME);
ApexInfo apexInfo = new ApexInfo();
apexInfo.isActive = isActive;
apexInfo.isFactory = isFactory;
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/BackgroundDexOptServiceUnitTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/BackgroundDexOptServiceUnitTest.java
index 47f449c..1be7e2e 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/BackgroundDexOptServiceUnitTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/BackgroundDexOptServiceUnitTest.java
@@ -223,7 +223,7 @@
/* expectedReschedule= */ false, /* expectedStatus= */ STATUS_OK,
/* totalJobFinishedWithParams= */ 1, /* expectedSkippedPackage= */ null);
runFullJob(mJobServiceForIdle, mJobParametersForIdle,
- /* expectedReschedule= */ true, /* expectedStatus= */ STATUS_OK,
+ /* expectedReschedule= */ false, /* expectedStatus= */ STATUS_OK,
/* totalJobFinishedWithParams= */ 1, /* expectedSkippedPackage= */ null);
}
@@ -241,7 +241,7 @@
assertThat(getFailedPackageNamesSecondary()).isEmpty();
runFullJob(mJobServiceForIdle, mJobParametersForIdle,
- /* expectedReschedule= */ true, /* expectedStatus= */ STATUS_OK,
+ /* expectedReschedule= */ false, /* expectedStatus= */ STATUS_OK,
/* totalJobFinishedWithParams= */ 1, /* expectedSkippedPackage= */ PACKAGE_AAA);
assertThat(getFailedPackageNamesPrimary()).containsExactly(PACKAGE_AAA);
@@ -256,7 +256,7 @@
mDexOptResultForPackageAAA = PackageDexOptimizer.DEX_OPT_PERFORMED;
runFullJob(mJobServiceForIdle, mJobParametersForIdle,
- /* expectedReschedule= */ true, /* expectedStatus= */ STATUS_OK,
+ /* expectedReschedule= */ false, /* expectedStatus= */ STATUS_OK,
/* totalJobFinishedWithParams= */ 2, /* expectedSkippedPackage= */ null);
assertThat(getFailedPackageNamesPrimary()).isEmpty();
@@ -393,7 +393,7 @@
mCancelThread.join(TEST_WAIT_TIMEOUT_MS);
// Always reschedule for periodic job
- verify(mJobServiceForIdle).jobFinished(mJobParametersForIdle, true);
+ verify(mJobServiceForIdle).jobFinished(mJobParametersForIdle, false);
verifyLastControlDexOptBlockingCall(false);
}
@@ -421,7 +421,7 @@
mCancelThread.join(TEST_WAIT_TIMEOUT_MS);
// Always reschedule for periodic job
- verify(mJobServiceForIdle).jobFinished(mJobParametersForIdle, true);
+ verify(mJobServiceForIdle).jobFinished(mJobParametersForIdle, false);
verify(mDexOptHelper, never()).controlDexOptBlocking(true);
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/InitAppsHelperTest.kt b/services/tests/mockingservicestests/src/com/android/server/pm/InitAppsHelperTest.kt
index 2165301..15b4975 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/InitAppsHelperTest.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/InitAppsHelperTest.kt
@@ -83,7 +83,7 @@
val pms = createPackageManagerService()
assertThat(pms.isFirstBoot).isEqualTo(true)
assertThat(pms.isDeviceUpgrading).isEqualTo(false)
- val initAppsHelper = InitAppsHelper(pms, rule.mocks().apexManager, null, null,
+ val initAppsHelper = InitAppsHelper(pms, rule.mocks().apexManager, null,
listOf<ScanPartition>())
assertThat(
initAppsHelper.systemScanFlags and PackageManagerService.SCAN_FIRST_BOOT_OR_UPGRADE)
@@ -98,7 +98,7 @@
val pms = createPackageManagerService()
assertThat(pms.isFirstBoot).isEqualTo(false)
assertThat(pms.isDeviceUpgrading).isEqualTo(true)
- val initAppsHelper = InitAppsHelper(pms, rule.mocks().apexManager, null, null,
+ val initAppsHelper = InitAppsHelper(pms, rule.mocks().apexManager, null,
listOf<ScanPartition>())
assertThat(
initAppsHelper.systemScanFlags and PackageManagerService.SCAN_FIRST_BOOT_OR_UPGRADE)
@@ -112,7 +112,7 @@
val pms = createPackageManagerService()
assertThat(pms.isFirstBoot).isEqualTo(false)
assertThat(pms.isDeviceUpgrading).isEqualTo(false)
- val initAppsHelper = InitAppsHelper(pms, rule.mocks().apexManager, null, null,
+ val initAppsHelper = InitAppsHelper(pms, rule.mocks().apexManager, null,
listOf<ScanPartition>())
assertThat(
initAppsHelper.systemScanFlags and PackageManagerService.SCAN_FIRST_BOOT_OR_UPGRADE)
@@ -126,7 +126,7 @@
val pms = createPackageManagerService()
assertThat(pms.isFirstBoot).isEqualTo(false)
assertThat(pms.isDeviceUpgrading).isEqualTo(true)
- val initAppsHelper = InitAppsHelper(pms, rule.mocks().apexManager, null, null,
+ val initAppsHelper = InitAppsHelper(pms, rule.mocks().apexManager, null,
listOf<ScanPartition>())
assertThat(
initAppsHelper.systemScanFlags and PackageManagerService.SCAN_FIRST_BOOT_OR_UPGRADE)
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
index dc7bcd6..dd6c733 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
@@ -78,14 +78,6 @@
import com.android.server.testutils.nullable
import com.android.server.testutils.whenever
import com.android.server.utils.WatchedArrayMap
-import java.io.File
-import java.io.IOException
-import java.nio.file.Files
-import java.security.PublicKey
-import java.security.cert.CertificateException
-import java.util.Arrays
-import java.util.Random
-import java.util.concurrent.FutureTask
import libcore.util.HexEncoding
import org.junit.Assert
import org.junit.rules.TestRule
@@ -94,6 +86,14 @@
import org.mockito.AdditionalMatchers.or
import org.mockito.Mockito
import org.mockito.quality.Strictness
+import java.io.File
+import java.io.IOException
+import java.nio.file.Files
+import java.security.PublicKey
+import java.security.cert.CertificateException
+import java.util.Arrays
+import java.util.Random
+import java.util.concurrent.FutureTask
/**
* A utility for mocking behavior of the system and dependencies when testing PackageManagerService
@@ -104,6 +104,9 @@
class MockSystem(withSession: (StaticMockitoSessionBuilder) -> Unit = {}) {
private val random = Random()
val mocks = Mocks()
+
+ // TODO: getBackingApexFile does not handle paths that aren't /apex
+ val apexDirectory = File("/apex")
val packageCacheDirectory: File =
Files.createTempDirectory("packageCache").toFile()
val rootDirectory: File =
@@ -297,7 +300,9 @@
whenever(mocks.systemConfig.sharedLibraries).thenReturn(DEFAULT_SHARED_LIBRARIES_LIST)
whenever(mocks.systemConfig.defaultVrComponents).thenReturn(ArraySet())
whenever(mocks.systemConfig.hiddenApiWhitelistedApps).thenReturn(ArraySet())
+ wheneverStatic { SystemProperties.set(anyString(), anyString()) }.thenDoNothing()
wheneverStatic { SystemProperties.getBoolean("fw.free_cache_v2", true) }.thenReturn(true)
+ wheneverStatic { Environment.getApexDirectory() }.thenReturn(apexDirectory)
wheneverStatic { Environment.getPackageCacheDirectory() }.thenReturn(packageCacheDirectory)
wheneverStatic { SystemProperties.digestOf("ro.build.fingerprint") }.thenReturn("cacheName")
wheneverStatic { Environment.getRootDirectory() }.thenReturn(rootDirectory)
diff --git a/services/tests/mockingservicestests/src/com/android/server/tare/AgentTrendCalculatorTest.java b/services/tests/mockingservicestests/src/com/android/server/tare/AgentTrendCalculatorTest.java
index 2fac31e..d477cb6 100644
--- a/services/tests/mockingservicestests/src/com/android/server/tare/AgentTrendCalculatorTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/tare/AgentTrendCalculatorTest.java
@@ -73,7 +73,12 @@
}
@Override
- long getHardSatiatedConsumptionLimit() {
+ long getMinSatiatedConsumptionLimit() {
+ return 0;
+ }
+
+ @Override
+ long getMaxSatiatedConsumptionLimit() {
return 0;
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/tare/AlarmManagerEconomicPolicyTest.java b/services/tests/mockingservicestests/src/com/android/server/tare/AlarmManagerEconomicPolicyTest.java
index fb3e8f2..84a61c7 100644
--- a/services/tests/mockingservicestests/src/com/android/server/tare/AlarmManagerEconomicPolicyTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/tare/AlarmManagerEconomicPolicyTest.java
@@ -132,8 +132,10 @@
public void testDefaults() {
assertEquals(EconomyManager.DEFAULT_AM_INITIAL_CONSUMPTION_LIMIT_CAKES,
mEconomicPolicy.getInitialSatiatedConsumptionLimit());
- assertEquals(EconomyManager.DEFAULT_AM_HARD_CONSUMPTION_LIMIT_CAKES,
- mEconomicPolicy.getHardSatiatedConsumptionLimit());
+ assertEquals(EconomyManager.DEFAULT_AM_MIN_CONSUMPTION_LIMIT_CAKES,
+ mEconomicPolicy.getMinSatiatedConsumptionLimit());
+ assertEquals(EconomyManager.DEFAULT_AM_MAX_CONSUMPTION_LIMIT_CAKES,
+ mEconomicPolicy.getMaxSatiatedConsumptionLimit());
final String pkgRestricted = "com.pkg.restricted";
when(mIrs.isPackageRestricted(anyInt(), eq(pkgRestricted))).thenReturn(true);
assertEquals(0, mEconomicPolicy.getMaxSatiatedBalance(0, pkgRestricted));
@@ -150,13 +152,15 @@
@Test
public void testConstantsUpdating_ValidValues() {
setDeviceConfigCakes(EconomyManager.KEY_AM_INITIAL_CONSUMPTION_LIMIT, arcToCake(5));
- setDeviceConfigCakes(EconomyManager.KEY_AM_HARD_CONSUMPTION_LIMIT, arcToCake(25));
+ setDeviceConfigCakes(EconomyManager.KEY_AM_MIN_CONSUMPTION_LIMIT, arcToCake(3));
+ setDeviceConfigCakes(EconomyManager.KEY_AM_MAX_CONSUMPTION_LIMIT, arcToCake(25));
setDeviceConfigCakes(EconomyManager.KEY_AM_MAX_SATIATED_BALANCE, arcToCake(10));
setDeviceConfigCakes(EconomyManager.KEY_AM_MIN_SATIATED_BALANCE_EXEMPTED, arcToCake(9));
setDeviceConfigCakes(EconomyManager.KEY_AM_MIN_SATIATED_BALANCE_OTHER_APP, arcToCake(7));
assertEquals(arcToCake(5), mEconomicPolicy.getInitialSatiatedConsumptionLimit());
- assertEquals(arcToCake(25), mEconomicPolicy.getHardSatiatedConsumptionLimit());
+ assertEquals(arcToCake(3), mEconomicPolicy.getMinSatiatedConsumptionLimit());
+ assertEquals(arcToCake(25), mEconomicPolicy.getMaxSatiatedConsumptionLimit());
final String pkgRestricted = "com.pkg.restricted";
when(mIrs.isPackageRestricted(anyInt(), eq(pkgRestricted))).thenReturn(true);
assertEquals(arcToCake(0), mEconomicPolicy.getMaxSatiatedBalance(0, pkgRestricted));
@@ -171,13 +175,15 @@
public void testConstantsUpdating_InvalidValues() {
// Test negatives.
setDeviceConfigCakes(EconomyManager.KEY_AM_INITIAL_CONSUMPTION_LIMIT, arcToCake(-5));
- setDeviceConfigCakes(EconomyManager.KEY_AM_HARD_CONSUMPTION_LIMIT, arcToCake(-5));
+ setDeviceConfigCakes(EconomyManager.KEY_AM_MIN_CONSUMPTION_LIMIT, arcToCake(-5));
+ setDeviceConfigCakes(EconomyManager.KEY_AM_MAX_CONSUMPTION_LIMIT, arcToCake(-5));
setDeviceConfigCakes(EconomyManager.KEY_AM_MAX_SATIATED_BALANCE, arcToCake(-1));
setDeviceConfigCakes(EconomyManager.KEY_AM_MIN_SATIATED_BALANCE_EXEMPTED, arcToCake(-2));
setDeviceConfigCakes(EconomyManager.KEY_AM_MIN_SATIATED_BALANCE_OTHER_APP, arcToCake(-3));
assertEquals(arcToCake(1), mEconomicPolicy.getInitialSatiatedConsumptionLimit());
- assertEquals(arcToCake(1), mEconomicPolicy.getHardSatiatedConsumptionLimit());
+ assertEquals(arcToCake(1), mEconomicPolicy.getMinSatiatedConsumptionLimit());
+ assertEquals(arcToCake(1), mEconomicPolicy.getMaxSatiatedConsumptionLimit());
final String pkgRestricted = "com.pkg.restricted";
when(mIrs.isPackageRestricted(anyInt(), eq(pkgRestricted))).thenReturn(true);
assertEquals(arcToCake(0), mEconomicPolicy.getMaxSatiatedBalance(0, pkgRestricted));
@@ -188,14 +194,16 @@
assertEquals(arcToCake(0), mEconomicPolicy.getMinSatiatedBalance(0, "com.any.other.app"));
// Test min+max reversed.
- setDeviceConfigCakes(EconomyManager.KEY_AM_INITIAL_CONSUMPTION_LIMIT, arcToCake(5));
- setDeviceConfigCakes(EconomyManager.KEY_AM_HARD_CONSUMPTION_LIMIT, arcToCake(3));
+ setDeviceConfigCakes(EconomyManager.KEY_AM_MIN_CONSUMPTION_LIMIT, arcToCake(5));
+ setDeviceConfigCakes(EconomyManager.KEY_AM_INITIAL_CONSUMPTION_LIMIT, arcToCake(4));
+ setDeviceConfigCakes(EconomyManager.KEY_AM_MAX_CONSUMPTION_LIMIT, arcToCake(3));
setDeviceConfigCakes(EconomyManager.KEY_AM_MAX_SATIATED_BALANCE, arcToCake(10));
setDeviceConfigCakes(EconomyManager.KEY_AM_MIN_SATIATED_BALANCE_EXEMPTED, arcToCake(11));
setDeviceConfigCakes(EconomyManager.KEY_AM_MIN_SATIATED_BALANCE_OTHER_APP, arcToCake(13));
assertEquals(arcToCake(5), mEconomicPolicy.getInitialSatiatedConsumptionLimit());
- assertEquals(arcToCake(5), mEconomicPolicy.getHardSatiatedConsumptionLimit());
+ assertEquals(arcToCake(5), mEconomicPolicy.getMinSatiatedConsumptionLimit());
+ assertEquals(arcToCake(5), mEconomicPolicy.getMaxSatiatedConsumptionLimit());
assertEquals(arcToCake(0), mEconomicPolicy.getMaxSatiatedBalance(0, pkgRestricted));
assertEquals(arcToCake(13), mEconomicPolicy.getMaxSatiatedBalance(0, "com.any.other.app"));
assertEquals(arcToCake(13), mEconomicPolicy.getMinSatiatedBalance(0, pkgExempted));
diff --git a/services/tests/mockingservicestests/src/com/android/server/tare/CompleteEconomicPolicyTest.java b/services/tests/mockingservicestests/src/com/android/server/tare/CompleteEconomicPolicyTest.java
index 6da4ab7..cad608f 100644
--- a/services/tests/mockingservicestests/src/com/android/server/tare/CompleteEconomicPolicyTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/tare/CompleteEconomicPolicyTest.java
@@ -155,9 +155,12 @@
assertEquals(EconomyManager.DEFAULT_JS_INITIAL_CONSUMPTION_LIMIT_CAKES
+ EconomyManager.DEFAULT_AM_INITIAL_CONSUMPTION_LIMIT_CAKES,
mEconomicPolicy.getInitialSatiatedConsumptionLimit());
- assertEquals(EconomyManager.DEFAULT_JS_HARD_CONSUMPTION_LIMIT_CAKES
- + EconomyManager.DEFAULT_AM_HARD_CONSUMPTION_LIMIT_CAKES,
- mEconomicPolicy.getHardSatiatedConsumptionLimit());
+ assertEquals(EconomyManager.DEFAULT_JS_MIN_CONSUMPTION_LIMIT_CAKES
+ + EconomyManager.DEFAULT_AM_MIN_CONSUMPTION_LIMIT_CAKES,
+ mEconomicPolicy.getMinSatiatedConsumptionLimit());
+ assertEquals(EconomyManager.DEFAULT_JS_MAX_CONSUMPTION_LIMIT_CAKES
+ + EconomyManager.DEFAULT_AM_MAX_CONSUMPTION_LIMIT_CAKES,
+ mEconomicPolicy.getMaxSatiatedConsumptionLimit());
final String pkgRestricted = "com.pkg.restricted";
when(mIrs.isPackageRestricted(anyInt(), eq(pkgRestricted))).thenReturn(true);
assertEquals(0, mEconomicPolicy.getMaxSatiatedBalance(0, pkgRestricted));
@@ -178,8 +181,10 @@
public void testConstantsUpdated() {
setDeviceConfigCakes(EconomyManager.KEY_JS_INITIAL_CONSUMPTION_LIMIT, arcToCake(4));
setDeviceConfigCakes(EconomyManager.KEY_AM_INITIAL_CONSUMPTION_LIMIT, arcToCake(6));
- setDeviceConfigCakes(EconomyManager.KEY_JS_HARD_CONSUMPTION_LIMIT, arcToCake(24));
- setDeviceConfigCakes(EconomyManager.KEY_AM_HARD_CONSUMPTION_LIMIT, arcToCake(26));
+ setDeviceConfigCakes(EconomyManager.KEY_JS_MIN_CONSUMPTION_LIMIT, arcToCake(2));
+ setDeviceConfigCakes(EconomyManager.KEY_AM_MIN_CONSUMPTION_LIMIT, arcToCake(3));
+ setDeviceConfigCakes(EconomyManager.KEY_JS_MAX_CONSUMPTION_LIMIT, arcToCake(24));
+ setDeviceConfigCakes(EconomyManager.KEY_AM_MAX_CONSUMPTION_LIMIT, arcToCake(26));
setDeviceConfigCakes(EconomyManager.KEY_JS_MAX_SATIATED_BALANCE, arcToCake(9));
setDeviceConfigCakes(EconomyManager.KEY_AM_MAX_SATIATED_BALANCE, arcToCake(11));
setDeviceConfigCakes(EconomyManager.KEY_JS_MIN_SATIATED_BALANCE_EXEMPTED, arcToCake(8));
@@ -188,7 +193,8 @@
setDeviceConfigCakes(EconomyManager.KEY_AM_MIN_SATIATED_BALANCE_OTHER_APP, arcToCake(2));
assertEquals(arcToCake(10), mEconomicPolicy.getInitialSatiatedConsumptionLimit());
- assertEquals(arcToCake(50), mEconomicPolicy.getHardSatiatedConsumptionLimit());
+ assertEquals(arcToCake(5), mEconomicPolicy.getMinSatiatedConsumptionLimit());
+ assertEquals(arcToCake(50), mEconomicPolicy.getMaxSatiatedConsumptionLimit());
final String pkgRestricted = "com.pkg.restricted";
when(mIrs.isPackageRestricted(anyInt(), eq(pkgRestricted))).thenReturn(true);
assertEquals(arcToCake(0), mEconomicPolicy.getMaxSatiatedBalance(0, pkgRestricted));
@@ -206,8 +212,10 @@
setDeviceConfigBoolean(EconomyManager.KEY_ENABLE_POLICY_JOB_SCHEDULER, false);
assertEquals(EconomyManager.DEFAULT_AM_INITIAL_CONSUMPTION_LIMIT_CAKES,
mEconomicPolicy.getInitialSatiatedConsumptionLimit());
- assertEquals(EconomyManager.DEFAULT_AM_HARD_CONSUMPTION_LIMIT_CAKES,
- mEconomicPolicy.getHardSatiatedConsumptionLimit());
+ assertEquals(EconomyManager.DEFAULT_AM_MIN_CONSUMPTION_LIMIT_CAKES,
+ mEconomicPolicy.getMinSatiatedConsumptionLimit());
+ assertEquals(EconomyManager.DEFAULT_AM_MAX_CONSUMPTION_LIMIT_CAKES,
+ mEconomicPolicy.getMaxSatiatedConsumptionLimit());
final String pkgRestricted = "com.pkg.restricted";
when(mIrs.isPackageRestricted(anyInt(), eq(pkgRestricted))).thenReturn(true);
assertEquals(0, mEconomicPolicy.getMaxSatiatedBalance(0, pkgRestricted));
@@ -229,8 +237,10 @@
setDeviceConfigBoolean(EconomyManager.KEY_ENABLE_POLICY_JOB_SCHEDULER, true);
assertEquals(EconomyManager.DEFAULT_JS_INITIAL_CONSUMPTION_LIMIT_CAKES,
mEconomicPolicy.getInitialSatiatedConsumptionLimit());
- assertEquals(EconomyManager.DEFAULT_JS_HARD_CONSUMPTION_LIMIT_CAKES,
- mEconomicPolicy.getHardSatiatedConsumptionLimit());
+ assertEquals(EconomyManager.DEFAULT_JS_MIN_CONSUMPTION_LIMIT_CAKES,
+ mEconomicPolicy.getMinSatiatedConsumptionLimit());
+ assertEquals(EconomyManager.DEFAULT_JS_MAX_CONSUMPTION_LIMIT_CAKES,
+ mEconomicPolicy.getMaxSatiatedConsumptionLimit());
when(mIrs.isPackageRestricted(anyInt(), eq(pkgRestricted))).thenReturn(true);
assertEquals(0, mEconomicPolicy.getMaxSatiatedBalance(0, pkgRestricted));
assertEquals(EconomyManager.DEFAULT_JS_MAX_SATIATED_BALANCE_CAKES,
diff --git a/services/tests/mockingservicestests/src/com/android/server/tare/JobSchedulerEconomicPolicyTest.java b/services/tests/mockingservicestests/src/com/android/server/tare/JobSchedulerEconomicPolicyTest.java
index b7bbcd75..ebf760c 100644
--- a/services/tests/mockingservicestests/src/com/android/server/tare/JobSchedulerEconomicPolicyTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/tare/JobSchedulerEconomicPolicyTest.java
@@ -132,8 +132,10 @@
public void testDefaults() {
assertEquals(EconomyManager.DEFAULT_JS_INITIAL_CONSUMPTION_LIMIT_CAKES,
mEconomicPolicy.getInitialSatiatedConsumptionLimit());
- assertEquals(EconomyManager.DEFAULT_JS_HARD_CONSUMPTION_LIMIT_CAKES,
- mEconomicPolicy.getHardSatiatedConsumptionLimit());
+ assertEquals(EconomyManager.DEFAULT_JS_MIN_CONSUMPTION_LIMIT_CAKES,
+ mEconomicPolicy.getMinSatiatedConsumptionLimit());
+ assertEquals(EconomyManager.DEFAULT_JS_MAX_CONSUMPTION_LIMIT_CAKES,
+ mEconomicPolicy.getMaxSatiatedConsumptionLimit());
final String pkgRestricted = "com.pkg.restricted";
when(mIrs.isPackageRestricted(anyInt(), eq(pkgRestricted))).thenReturn(true);
@@ -171,7 +173,8 @@
@Test
public void testConstantsUpdating_ValidValues() {
setDeviceConfigCakes(EconomyManager.KEY_JS_INITIAL_CONSUMPTION_LIMIT, arcToCake(5));
- setDeviceConfigCakes(EconomyManager.KEY_JS_HARD_CONSUMPTION_LIMIT, arcToCake(25));
+ setDeviceConfigCakes(EconomyManager.KEY_JS_MIN_CONSUMPTION_LIMIT, arcToCake(2));
+ setDeviceConfigCakes(EconomyManager.KEY_JS_MAX_CONSUMPTION_LIMIT, arcToCake(25));
setDeviceConfigCakes(EconomyManager.KEY_JS_MAX_SATIATED_BALANCE, arcToCake(10));
setDeviceConfigCakes(EconomyManager.KEY_JS_MIN_SATIATED_BALANCE_EXEMPTED, arcToCake(6));
setDeviceConfigCakes(EconomyManager.KEY_JS_MIN_SATIATED_BALANCE_OTHER_APP, arcToCake(4));
@@ -179,7 +182,8 @@
arcToCake(1));
assertEquals(arcToCake(5), mEconomicPolicy.getInitialSatiatedConsumptionLimit());
- assertEquals(arcToCake(25), mEconomicPolicy.getHardSatiatedConsumptionLimit());
+ assertEquals(arcToCake(2), mEconomicPolicy.getMinSatiatedConsumptionLimit());
+ assertEquals(arcToCake(25), mEconomicPolicy.getMaxSatiatedConsumptionLimit());
final String pkgRestricted = "com.pkg.restricted";
when(mIrs.isPackageRestricted(anyInt(), eq(pkgRestricted))).thenReturn(true);
assertEquals(arcToCake(0), mEconomicPolicy.getMaxSatiatedBalance(0, pkgRestricted));
@@ -198,7 +202,8 @@
public void testConstantsUpdating_InvalidValues() {
// Test negatives.
setDeviceConfigCakes(EconomyManager.KEY_JS_INITIAL_CONSUMPTION_LIMIT, arcToCake(-5));
- setDeviceConfigCakes(EconomyManager.KEY_JS_HARD_CONSUMPTION_LIMIT, arcToCake(-5));
+ setDeviceConfigCakes(EconomyManager.KEY_JS_MIN_CONSUMPTION_LIMIT, arcToCake(-5));
+ setDeviceConfigCakes(EconomyManager.KEY_JS_MAX_CONSUMPTION_LIMIT, arcToCake(-5));
setDeviceConfigCakes(EconomyManager.KEY_JS_MAX_SATIATED_BALANCE, arcToCake(-1));
setDeviceConfigCakes(EconomyManager.KEY_JS_MIN_SATIATED_BALANCE_EXEMPTED, arcToCake(-2));
setDeviceConfigCakes(EconomyManager.KEY_JS_MIN_SATIATED_BALANCE_OTHER_APP, arcToCake(-3));
@@ -206,7 +211,8 @@
arcToCake(-4));
assertEquals(arcToCake(1), mEconomicPolicy.getInitialSatiatedConsumptionLimit());
- assertEquals(arcToCake(1), mEconomicPolicy.getHardSatiatedConsumptionLimit());
+ assertEquals(arcToCake(1), mEconomicPolicy.getMinSatiatedConsumptionLimit());
+ assertEquals(arcToCake(1), mEconomicPolicy.getMaxSatiatedConsumptionLimit());
final String pkgRestricted = "com.pkg.restricted";
when(mIrs.isPackageRestricted(anyInt(), eq(pkgRestricted))).thenReturn(true);
assertEquals(arcToCake(0), mEconomicPolicy.getMaxSatiatedBalance(0, pkgRestricted));
@@ -221,14 +227,16 @@
mEconomicPolicy.getMinSatiatedBalance(0, pkgUpdater));
// Test min+max reversed.
- setDeviceConfigCakes(EconomyManager.KEY_JS_INITIAL_CONSUMPTION_LIMIT, arcToCake(5));
- setDeviceConfigCakes(EconomyManager.KEY_JS_HARD_CONSUMPTION_LIMIT, arcToCake(3));
+ setDeviceConfigCakes(EconomyManager.KEY_JS_MIN_CONSUMPTION_LIMIT, arcToCake(5));
+ setDeviceConfigCakes(EconomyManager.KEY_JS_INITIAL_CONSUMPTION_LIMIT, arcToCake(4));
+ setDeviceConfigCakes(EconomyManager.KEY_JS_MAX_CONSUMPTION_LIMIT, arcToCake(3));
setDeviceConfigCakes(EconomyManager.KEY_JS_MAX_SATIATED_BALANCE, arcToCake(10));
setDeviceConfigCakes(EconomyManager.KEY_JS_MIN_SATIATED_BALANCE_EXEMPTED, arcToCake(11));
setDeviceConfigCakes(EconomyManager.KEY_JS_MIN_SATIATED_BALANCE_OTHER_APP, arcToCake(13));
assertEquals(arcToCake(5), mEconomicPolicy.getInitialSatiatedConsumptionLimit());
- assertEquals(arcToCake(5), mEconomicPolicy.getHardSatiatedConsumptionLimit());
+ assertEquals(arcToCake(5), mEconomicPolicy.getMinSatiatedConsumptionLimit());
+ assertEquals(arcToCake(5), mEconomicPolicy.getMaxSatiatedConsumptionLimit());
assertEquals(arcToCake(0), mEconomicPolicy.getMaxSatiatedBalance(0, pkgRestricted));
assertEquals(arcToCake(13), mEconomicPolicy.getMaxSatiatedBalance(0, "com.any.other.app"));
assertEquals(arcToCake(13), mEconomicPolicy.getMinSatiatedBalance(0, pkgExempted));
diff --git a/services/tests/mockingservicestests/src/com/android/server/utils/AlarmQueueTest.java b/services/tests/mockingservicestests/src/com/android/server/utils/AlarmQueueTest.java
index 00d7541..a3a49d70 100644
--- a/services/tests/mockingservicestests/src/com/android/server/utils/AlarmQueueTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/utils/AlarmQueueTest.java
@@ -35,6 +35,7 @@
import android.app.AlarmManager;
import android.content.Context;
+import android.os.Handler;
import android.os.Looper;
import android.os.SystemClock;
import android.util.ArraySet;
@@ -222,7 +223,8 @@
alarmQueue.addAlarm("com.android.test.1", nowElapsed + HOUR_IN_MILLIS);
verify(mAlarmManager, timeout(1000).times(1)).setWindow(
- anyInt(), eq(nowElapsed + HOUR_IN_MILLIS), anyLong(), eq(ALARM_TAG), any(), any());
+ anyInt(), eq(nowElapsed + HOUR_IN_MILLIS), anyLong(), eq(ALARM_TAG), any(), any(
+ Handler.class));
}
@Test
diff --git a/services/tests/mockingservicestests/src/com/android/server/utils/quota/CountQuotaTrackerTest.java b/services/tests/mockingservicestests/src/com/android/server/utils/quota/CountQuotaTrackerTest.java
index 608b64e..0d14c9f 100644
--- a/services/tests/mockingservicestests/src/com/android/server/utils/quota/CountQuotaTrackerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/utils/quota/CountQuotaTrackerTest.java
@@ -589,14 +589,14 @@
// No sessions saved yet.
mQuotaTracker.maybeScheduleStartAlarmLocked(TEST_USER_ID, TEST_PACKAGE, TEST_TAG);
verify(mAlarmManager, never()).setWindow(
- anyInt(), anyLong(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any());
+ anyInt(), anyLong(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any(Handler.class));
// Test with timing sessions out of window.
final long now = mInjector.getElapsedRealtime();
logEventsAt(TEST_USER_ID, TEST_PACKAGE, TEST_TAG, now - 10 * HOUR_IN_MILLIS, 20);
mQuotaTracker.maybeScheduleStartAlarmLocked(TEST_USER_ID, TEST_PACKAGE, TEST_TAG);
verify(mAlarmManager, never()).setWindow(
- anyInt(), anyLong(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any());
+ anyInt(), anyLong(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any(Handler.class));
// Test with timing sessions in window but still in quota.
final long start = now - (6 * HOUR_IN_MILLIS);
@@ -604,25 +604,27 @@
logEventsAt(TEST_USER_ID, TEST_PACKAGE, TEST_TAG, start, 5);
mQuotaTracker.maybeScheduleStartAlarmLocked(TEST_USER_ID, TEST_PACKAGE, TEST_TAG);
verify(mAlarmManager, never()).setWindow(
- anyInt(), anyLong(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any());
+ anyInt(), anyLong(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any(Handler.class));
// Add some more sessions, but still in quota.
logEventsAt(TEST_USER_ID, TEST_PACKAGE, TEST_TAG, now - 3 * HOUR_IN_MILLIS, 1);
logEventsAt(TEST_USER_ID, TEST_PACKAGE, TEST_TAG, now - HOUR_IN_MILLIS, 3);
mQuotaTracker.maybeScheduleStartAlarmLocked(TEST_USER_ID, TEST_PACKAGE, TEST_TAG);
verify(mAlarmManager, never()).setWindow(
- anyInt(), anyLong(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any());
+ anyInt(), anyLong(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any(Handler.class));
// Test when out of quota.
logEventsAt(TEST_USER_ID, TEST_PACKAGE, TEST_TAG, now - HOUR_IN_MILLIS, 1);
mQuotaTracker.maybeScheduleStartAlarmLocked(TEST_USER_ID, TEST_PACKAGE, TEST_TAG);
verify(mAlarmManager, timeout(1000).times(1)).setWindow(
- anyInt(), eq(expectedAlarmTime), anyLong(), eq(TAG_QUOTA_CHECK), any(), any());
+ anyInt(), eq(expectedAlarmTime), anyLong(), eq(TAG_QUOTA_CHECK), any(),
+ any(Handler.class));
// Alarm already scheduled, so make sure it's not scheduled again.
mQuotaTracker.maybeScheduleStartAlarmLocked(TEST_USER_ID, TEST_PACKAGE, TEST_TAG);
verify(mAlarmManager, times(1)).setWindow(
- anyInt(), eq(expectedAlarmTime), anyLong(), eq(TAG_QUOTA_CHECK), any(), any());
+ anyInt(), eq(expectedAlarmTime), anyLong(), eq(TAG_QUOTA_CHECK), any(),
+ any(Handler.class));
}
/** Tests that the start alarm is properly rescheduled if the app's category is changed. */
@@ -656,7 +658,8 @@
mCategorizer.mCategoryToUse = ACTIVE_BUCKET_CATEGORY;
mQuotaTracker.maybeScheduleStartAlarmLocked(TEST_USER_ID, TEST_PACKAGE, TEST_TAG);
inOrder.verify(mAlarmManager, never())
- .setWindow(anyInt(), anyLong(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any());
+ .setWindow(anyInt(), anyLong(), anyLong(), eq(TAG_QUOTA_CHECK), any(),
+ any(Handler.class));
inOrder.verify(mAlarmManager, never()).cancel(any(AlarmManager.OnAlarmListener.class));
// And down from there.
@@ -665,41 +668,42 @@
mQuotaTracker.maybeScheduleStartAlarmLocked(TEST_USER_ID, TEST_PACKAGE, TEST_TAG);
inOrder.verify(mAlarmManager, timeout(1000).times(1))
.setWindow(anyInt(), eq(expectedWorkingAlarmTime), anyLong(),
- eq(TAG_QUOTA_CHECK), any(), any());
+ eq(TAG_QUOTA_CHECK), any(), any(Handler.class));
final long expectedFrequentAlarmTime = outOfQuotaTime + (8 * HOUR_IN_MILLIS);
mCategorizer.mCategoryToUse = FREQUENT_BUCKET_CATEGORY;
mQuotaTracker.maybeScheduleStartAlarmLocked(TEST_USER_ID, TEST_PACKAGE, TEST_TAG);
inOrder.verify(mAlarmManager, timeout(1000).times(1))
.setWindow(anyInt(), eq(expectedFrequentAlarmTime), anyLong(),
- eq(TAG_QUOTA_CHECK), any(), any());
+ eq(TAG_QUOTA_CHECK), any(), any(Handler.class));
final long expectedRareAlarmTime = outOfQuotaTime + (24 * HOUR_IN_MILLIS);
mCategorizer.mCategoryToUse = RARE_BUCKET_CATEGORY;
mQuotaTracker.maybeScheduleStartAlarmLocked(TEST_USER_ID, TEST_PACKAGE, TEST_TAG);
inOrder.verify(mAlarmManager, timeout(1000).times(1))
.setWindow(anyInt(), eq(expectedRareAlarmTime), anyLong(),
- eq(TAG_QUOTA_CHECK), any(), any());
+ eq(TAG_QUOTA_CHECK), any(), any(Handler.class));
// And back up again.
mCategorizer.mCategoryToUse = FREQUENT_BUCKET_CATEGORY;
mQuotaTracker.maybeScheduleStartAlarmLocked(TEST_USER_ID, TEST_PACKAGE, TEST_TAG);
inOrder.verify(mAlarmManager, timeout(1000).times(1))
.setWindow(anyInt(), eq(expectedFrequentAlarmTime), anyLong(),
- eq(TAG_QUOTA_CHECK), any(), any());
+ eq(TAG_QUOTA_CHECK), any(), any(Handler.class));
mCategorizer.mCategoryToUse = WORKING_SET_BUCKET_CATEGORY;
mQuotaTracker.maybeScheduleStartAlarmLocked(TEST_USER_ID, TEST_PACKAGE, TEST_TAG);
inOrder.verify(mAlarmManager, timeout(1000).times(1))
.setWindow(anyInt(), eq(expectedWorkingAlarmTime), anyLong(),
- eq(TAG_QUOTA_CHECK), any(), any());
+ eq(TAG_QUOTA_CHECK), any(), any(Handler.class));
mCategorizer.mCategoryToUse = ACTIVE_BUCKET_CATEGORY;
mQuotaTracker.maybeScheduleStartAlarmLocked(TEST_USER_ID, TEST_PACKAGE, TEST_TAG);
inOrder.verify(mAlarmManager, timeout(1000).times(1))
.cancel(any(AlarmManager.OnAlarmListener.class));
inOrder.verify(mAlarmManager, timeout(1000).times(0))
- .setWindow(anyInt(), anyLong(), anyLong(), eq(TAG_QUOTA_CHECK), any(), any());
+ .setWindow(anyInt(), anyLong(), anyLong(), eq(TAG_QUOTA_CHECK), any(),
+ any(Handler.class));
}
@Test
diff --git a/services/tests/mockingservicestests/utils-mockito/com/android/server/extendedtestutils/ExtendedMockitoUtils.kt b/services/tests/mockingservicestests/utils-mockito/com/android/server/extendedtestutils/ExtendedMockitoUtils.kt
index 72ae77e..a0a67439 100644
--- a/services/tests/mockingservicestests/utils-mockito/com/android/server/extendedtestutils/ExtendedMockitoUtils.kt
+++ b/services/tests/mockingservicestests/utils-mockito/com/android/server/extendedtestutils/ExtendedMockitoUtils.kt
@@ -33,9 +33,14 @@
override fun thenReturn(value: T) {
ExtendedMockito.doReturn(value).wheneverStatic(mockedMethod)
}
+
+ override fun thenDoNothing() {
+ ExtendedMockito.doNothing().wheneverStatic(mockedMethod)
+ }
}
interface CustomStaticStubber<T> {
fun thenAnswer(answer: Answer<T>)
fun thenReturn(value: T)
+ fun thenDoNothing()
}
diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp
index 8a932f1..61bb57e 100644
--- a/services/tests/servicestests/Android.bp
+++ b/services/tests/servicestests/Android.bp
@@ -124,9 +124,6 @@
":PackageParserTestApp4",
":PackageParserTestApp5",
":PackageParserTestApp6",
- ":apex.test",
- ":test.rebootless_apex_v1",
- ":test.rebootless_apex_v2",
":com.android.apex.cts.shim.v1_prebuilt",
":com.android.apex.cts.shim.v2_different_certificate_prebuilt",
":com.android.apex.cts.shim.v2_unsigned_apk_container_prebuilt",
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/BaseClientMonitorTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BaseClientMonitorTest.java
index 8e6d90c..3a9c0f0 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/BaseClientMonitorTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BaseClientMonitorTest.java
@@ -107,7 +107,7 @@
assertThat(mClientMonitor.getRequestId()).isEqualTo(id);
}
- private class TestClientMonitor extends BaseClientMonitor implements Interruptable {
+ private class TestClientMonitor extends BaseClientMonitor {
public boolean mCanceled = false;
TestClientMonitor() {
@@ -129,5 +129,10 @@
public void cancelWithoutStarting(@NonNull ClientMonitorCallback callback) {
mCanceled = true;
}
+
+ @Override
+ public boolean isInterruptable() {
+ return true;
+ }
}
}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerOperationTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerOperationTest.java
index 9e9d703..3c77a35 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerOperationTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerOperationTest.java
@@ -57,11 +57,16 @@
public interface FakeHal {}
public abstract static class InterruptableMonitor<T>
- extends HalClientMonitor<T> implements Interruptable {
+ extends HalClientMonitor<T> {
public InterruptableMonitor() {
super(null, null, null, null, 0, null, 0, 0,
mock(BiometricLogger.class), mock(BiometricContext.class));
}
+
+ @Override
+ public boolean isInterruptable() {
+ return true;
+ }
}
@Rule
@@ -293,7 +298,6 @@
assertThat(mOperation.isCanceling()).isTrue();
verify(mClientMonitor).cancel();
- verify(mClientMonitor, never()).cancelWithoutStarting(any());
verify(mClientMonitor, never()).destroy();
mStartedCallbackCaptor.getValue().onClientFinished(mClientMonitor, true);
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java
index ffacbf3..9f30c75 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java
@@ -34,7 +34,6 @@
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import static org.mockito.Mockito.withSettings;
import android.content.Context;
import android.hardware.biometrics.BiometricAuthenticator;
@@ -475,8 +474,8 @@
@Test
public void testInterruptPrecedingClients_whenExpected() {
- final BaseClientMonitor interruptableMonitor = mock(BaseClientMonitor.class,
- withSettings().extraInterfaces(Interruptable.class));
+ final BaseClientMonitor interruptableMonitor = mock(BaseClientMonitor.class);
+ when(interruptableMonitor.isInterruptable()).thenReturn(true);
final BaseClientMonitor interrupter = mock(BaseClientMonitor.class);
when(interrupter.interruptsPrecedingClients()).thenReturn(true);
@@ -491,8 +490,8 @@
@Test
public void testDoesNotInterruptPrecedingClients_whenNotExpected() {
- final BaseClientMonitor interruptableMonitor = mock(BaseClientMonitor.class,
- withSettings().extraInterfaces(Interruptable.class));
+ final BaseClientMonitor interruptableMonitor = mock(BaseClientMonitor.class);
+ when(interruptableMonitor.isInterruptable()).thenReturn(true);
final BaseClientMonitor interrupter = mock(BaseClientMonitor.class);
when(interrupter.interruptsPrecedingClients()).thenReturn(false);
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
index 1b867be..8f6bee1 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
@@ -92,7 +92,6 @@
HdmiCecConfig hdmiCecConfig = new FakeHdmiCecConfig(mContextSpy);
mLocalDeviceTypes.add(HdmiDeviceInfo.DEVICE_PLAYBACK);
- mLocalDeviceTypes.add(DEVICE_AUDIO_SYSTEM);
mHdmiControlServiceSpy = spy(new HdmiControlService(mContextSpy, mLocalDeviceTypes,
new FakeAudioDeviceVolumeManagerWrapper()));
@@ -480,6 +479,7 @@
HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION,
HdmiControlManager.HDMI_CEC_VERSION_2_0);
mHdmiControlServiceSpy.setControlEnabled(HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
+ mHdmiControlServiceSpy.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
mTestLooper.dispatchAll();
mNativeWrapper.onCecMessage(HdmiCecMessageBuilder.buildGiveFeatures(Constants.ADDR_TV,
@@ -501,6 +501,7 @@
HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION,
HdmiControlManager.HDMI_CEC_VERSION_1_4_B);
mHdmiControlServiceSpy.setControlEnabled(HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
+ mHdmiControlServiceSpy.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
mTestLooper.dispatchAll();
HdmiCecMessage reportFeatures = ReportFeaturesMessage.build(
@@ -517,6 +518,7 @@
HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION,
HdmiControlManager.HDMI_CEC_VERSION_2_0);
mHdmiControlServiceSpy.setControlEnabled(HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
+ mHdmiControlServiceSpy.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
mTestLooper.dispatchAll();
HdmiCecMessage reportFeatures = ReportFeaturesMessage.build(
diff --git a/services/tests/servicestests/src/com/android/server/power/stats/CpuWakeupStatsTest.java b/services/tests/servicestests/src/com/android/server/power/stats/CpuWakeupStatsTest.java
index 7731a32..c2556e9 100644
--- a/services/tests/servicestests/src/com/android/server/power/stats/CpuWakeupStatsTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/stats/CpuWakeupStatsTest.java
@@ -44,7 +44,9 @@
public class CpuWakeupStatsTest {
private static final String KERNEL_REASON_ALARM_IRQ = "120 test.alarm.device";
private static final String KERNEL_REASON_UNKNOWN_IRQ = "140 test.unknown.device";
- private static final String KERNEL_REASON_UNKNOWN = "unsupported-free-form-reason";
+ private static final String KERNEL_REASON_UNKNOWN = "free-form-reason test.alarm.device";
+ private static final String KERNEL_REASON_UNSUPPORTED = "-1 test.alarm.device";
+ private static final String KERNEL_REASON_ABORT = "Abort: due to test.alarm.device";
private static final int TEST_UID_1 = 13239823;
private static final int TEST_UID_2 = 25268423;
@@ -57,6 +59,7 @@
@Test
public void removesOldWakeups() {
+ // The xml resource doesn't matter for this test.
final CpuWakeupStats obj = new CpuWakeupStats(sContext, R.xml.irq_device_map_1);
final Set<Long> timestamps = new HashSet<>();
@@ -165,11 +168,36 @@
obj.noteWakeupTimeAndReason(wakeupTime, 34, KERNEL_REASON_UNKNOWN);
- // Unrelated subsystems, should be ignored.
+ // Should be ignored as this type of wakeup is unsupported.
obj.noteWakingActivity(CPU_WAKEUP_SUBSYSTEM_ALARM, wakeupTime + 5, TEST_UID_3);
obj.noteWakingActivity(CPU_WAKEUP_SUBSYSTEM_ALARM, wakeupTime - 3, TEST_UID_4);
// There should be nothing in the attribution map.
assertThat(obj.mWakeupAttribution.size()).isEqualTo(0);
}
+
+ @Test
+ public void unsupportedAttribution() {
+ final CpuWakeupStats obj = new CpuWakeupStats(sContext, R.xml.irq_device_map_3);
+
+ long wakeupTime = 970934;
+ obj.noteWakeupTimeAndReason(wakeupTime, 34, KERNEL_REASON_UNSUPPORTED);
+
+ // Should be ignored as this type of wakeup is unsupported.
+ obj.noteWakingActivity(CPU_WAKEUP_SUBSYSTEM_ALARM, wakeupTime + 5, TEST_UID_3);
+ obj.noteWakingActivity(CPU_WAKEUP_SUBSYSTEM_ALARM, wakeupTime - 3, TEST_UID_4);
+
+ // There should be nothing in the attribution map.
+ assertThat(obj.mWakeupAttribution.size()).isEqualTo(0);
+
+ wakeupTime = 883124;
+ obj.noteWakeupTimeAndReason(wakeupTime, 3, KERNEL_REASON_ABORT);
+
+ // Should be ignored as this type of wakeup is unsupported.
+ obj.noteWakingActivity(CPU_WAKEUP_SUBSYSTEM_ALARM, wakeupTime + 2, TEST_UID_1, TEST_UID_4);
+ obj.noteWakingActivity(CPU_WAKEUP_SUBSYSTEM_ALARM, wakeupTime - 5, TEST_UID_3);
+
+ // There should be nothing in the attribution map.
+ assertThat(obj.mWakeupAttribution.size()).isEqualTo(0);
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/utils/EventLoggerTest.java b/services/tests/servicestests/src/com/android/server/utils/EventLoggerTest.java
index 4762696..aafc16d 100644
--- a/services/tests/servicestests/src/com/android/server/utils/EventLoggerTest.java
+++ b/services/tests/servicestests/src/com/android/server/utils/EventLoggerTest.java
@@ -29,8 +29,10 @@
import java.io.PrintWriter;
import java.io.StringWriter;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
+import java.util.List;
@SmallTest
@RunWith(Enclosed.class)
@@ -51,17 +53,25 @@
private StringWriter mTestStringWriter;
private PrintWriter mTestPrintWriter;
+ private TestDumpSink mTestConsumer;
private EventLogger mEventLogger;
@Before
public void setUp() {
mTestStringWriter = new StringWriter();
mTestPrintWriter = new PrintWriter(mTestStringWriter);
+ mTestConsumer = new TestDumpSink();
mEventLogger = new EventLogger(EVENTS_LOGGER_SIZE, EVENTS_LOGGER_TAG);
}
@Test
- public void testThatConsumeOfEmptyLoggerProducesEmptyList() {
+ public void testThatConsumerProducesEmptyListFromEmptyLog() {
+ mEventLogger.dump(mTestConsumer);
+ assertThat(mTestConsumer.getLastKnownConsumedEvents()).isEmpty();
+ }
+
+ @Test
+ public void testThatPrintWriterProducesEmptyListFromEmptyLog() {
mEventLogger.dump(mTestPrintWriter);
assertThat(mTestStringWriter.toString()).isEmpty();
}
@@ -102,10 +112,12 @@
});
}
+ private TestDumpSink mTestConsumer;
private EventLogger mEventLogger;
private final StringWriter mTestStringWriter;
private final PrintWriter mTestPrintWriter;
+
private final EventLogger.Event[] mEventsToInsert;
private final EventLogger.Event[] mExpectedEvents;
@@ -119,11 +131,25 @@
@Before
public void setUp() {
+ mTestConsumer = new TestDumpSink();
mEventLogger = new EventLogger(EVENTS_LOGGER_SIZE, EVENTS_LOGGER_TAG);
}
@Test
- public void testThatLoggingWorksAsExpected() {
+ public void testThatConsumerDumpsEventsAsExpected() {
+ for (EventLogger.Event event: mEventsToInsert) {
+ mEventLogger.enqueue(event);
+ }
+
+ mEventLogger.dump(mTestConsumer);
+
+ assertThat(mTestConsumer.getLastKnownConsumedEvents())
+ .containsExactlyElementsIn(mExpectedEvents);
+ }
+
+
+ @Test
+ public void testThatPrintWriterDumpsEventsAsExpected() {
for (EventLogger.Event event: mEventsToInsert) {
mEventLogger.enqueue(event);
}
@@ -149,11 +175,27 @@
return stringWriter.toString();
}
- private static class TestEvent extends EventLogger.Event {
+
+ private static final class TestEvent extends EventLogger.Event {
@Override
public String eventToString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
}
+
+ private static final class TestDumpSink implements EventLogger.DumpSink {
+
+ private final ArrayList<EventLogger.Event> mEvents = new ArrayList<>();
+
+ @Override
+ public void sink(String tag, List<EventLogger.Event> events) {
+ mEvents.clear();
+ mEvents.addAll(events);
+ }
+
+ public ArrayList<EventLogger.Event> getLastKnownConsumedEvents() {
+ return new ArrayList<>(mEvents);
+ }
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
index d4c9087..35b9710 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
@@ -1520,6 +1520,29 @@
transition.abort();
}
+ @Test
+ public void testCollectReparentChange() {
+ registerTestTransitionPlayer();
+
+ // Reparent activity in transition.
+ final Task lastParent = createTask(mDisplayContent);
+ final Task newParent = createTask(mDisplayContent);
+ final ActivityRecord activity = createActivityRecord(lastParent);
+ doReturn(true).when(lastParent).shouldRemoveSelfOnLastChildRemoval();
+ doNothing().when(activity).setDropInputMode(anyInt());
+ activity.mVisibleRequested = true;
+
+ final Transition transition = new Transition(TRANSIT_CHANGE, 0 /* flags */,
+ activity.mTransitionController, mWm.mSyncEngine);
+ activity.mTransitionController.moveToCollecting(transition);
+ transition.collect(activity);
+ activity.reparent(newParent, POSITION_TOP);
+
+ // ChangeInfo#mCommonAncestor should be set after reparent.
+ final Transition.ChangeInfo change = transition.mChanges.get(activity);
+ assertEquals(newParent.getDisplayArea(), change.mCommonAncestor);
+ }
+
private static void makeTaskOrganized(Task... tasks) {
final ITaskOrganizer organizer = mock(ITaskOrganizer.class);
for (Task t : tasks) {
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index d314a65..7be40b8 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -1147,8 +1147,12 @@
"carrier_data_call_apn_retry_after_disconnect_long";
/**
- * Data call setup permanent failure causes by the carrier
+ * Data call setup permanent failure causes by the carrier.
+ *
+ * @deprecated This API key was added in mistake and is not used anymore by the telephony data
+ * frameworks.
*/
+ @Deprecated
public static final String KEY_CARRIER_DATA_CALL_PERMANENT_FAILURE_STRINGS =
"carrier_data_call_permanent_failure_strings";
@@ -2103,6 +2107,16 @@
* is immediately closed (disabling keep-alive).
*/
public static final String KEY_MMS_CLOSE_CONNECTION_BOOL = "mmsCloseConnection";
+ /**
+ * Waiting time in milliseconds used before releasing an MMS data call. Not tearing down an MMS
+ * data connection immediately helps to reduce the message delivering latency if messaging
+ * continues between all parties in the conversation since the same data connection can be
+ * reused for further messages.
+ *
+ * This timer will control how long the data call will be kept alive before being torn down.
+ */
+ public static final String KEY_MMS_NETWORK_RELEASE_TIMEOUT_MILLIS_INT =
+ "mms_network_release_timeout_millis_int";
/**
* The flatten {@link android.content.ComponentName componentName} of the activity that can
@@ -8436,7 +8450,8 @@
*
* The syntax of the retry rule:
* 1. Retry based on {@link NetworkCapabilities}. Note that only APN-type network capabilities
- * are supported.
+ * are supported. If the capabilities are not specified, then the retry rule only applies
+ * to the current failed APN used in setup data call request.
* "capabilities=[netCaps1|netCaps2|...], [retry_interval=n1|n2|n3|n4...], [maximum_retries=n]"
*
* 2. Retry based on {@link DataFailCause}
@@ -8447,15 +8462,16 @@
* "capabilities=[netCaps1|netCaps2|...], fail_causes=[cause1|cause2|cause3|...],
* [retry_interval=n1|n2|n3|n4...], [maximum_retries=n]"
*
+ * 4. Permanent fail causes (no timer-based retry) on the current failed APN. Retry interval
+ * is specified for retrying the next available APN.
+ * "permanent_fail_causes=8|27|28|29|30|32|33|35|50|51|111|-5|-6|65537|65538|-3|65543|65547|
+ * 2252|2253|2254, retry_interval=2500"
+ *
* For example,
* "capabilities=eims, retry_interval=1000, maximum_retries=20" means if the attached
* network request is emergency, then retry data network setup every 1 second for up to 20
* times.
*
- * "fail_causes=8|27|28|29|30|32|33|35|50|51|111|-5|-6|65537|65538|-3|2253|2254
- * , maximum_retries=0" means for those fail causes, never retry with timers. Note that
- * when environment changes, retry can still happen.
- *
* "capabilities=internet|enterprise|dun|ims|fota, retry_interval=2500|3000|"
* "5000|10000|15000|20000|40000|60000|120000|240000|600000|1200000|1800000"
* "1800000, maximum_retries=20" means for those capabilities, retry happens in 2.5s, 3s, 5s,
@@ -8758,6 +8774,22 @@
"premium_capability_purchase_condition_backoff_hysteresis_time_millis_long";
/**
+ * The amount of time in milliseconds within which the network must set up a slicing
+ * configuration for the premium capability after
+ * {@link TelephonyManager#purchasePremiumCapability(int, Executor, Consumer)}
+ * returns {@link TelephonyManager#PURCHASE_PREMIUM_CAPABILITY_RESULT_SUCCESS}.
+ * During the setup time, calls to
+ * {@link TelephonyManager#purchasePremiumCapability(int, Executor, Consumer)} will return
+ * {@link TelephonyManager#PURCHASE_PREMIUM_CAPABILITY_RESULT_PENDING_NETWORK_SETUP}.
+ * If the network fails set up a slicing configuration for the premium capability within the
+ * setup time, subsequent purchase requests will be allowed to go through again.
+ *
+ * The default value is 5 minutes.
+ */
+ public static final String KEY_PREMIUM_CAPABILITY_NETWORK_SETUP_TIME_MILLIS_LONG =
+ "premium_capability_network_setup_time_millis_long";
+
+ /**
* The URL to redirect to when the user clicks on the notification for a network boost via
* premium capabilities after applications call
* {@link TelephonyManager#purchasePremiumCapability(int, Executor, Consumer)}.
@@ -9069,6 +9101,7 @@
sDefaults.putInt(KEY_MMS_SMS_TO_MMS_TEXT_LENGTH_THRESHOLD_INT, -1);
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.putString(KEY_MMS_EMAIL_GATEWAY_NUMBER_STRING, "");
sDefaults.putString(KEY_MMS_HTTP_PARAMS_STRING, "");
sDefaults.putString(KEY_MMS_NAI_SUFFIX_STRING, "");
@@ -9432,8 +9465,13 @@
sDefaults.putStringArray(
KEY_TELEPHONY_DATA_SETUP_RETRY_RULES_STRING_ARRAY, new String[] {
"capabilities=eims, retry_interval=1000, maximum_retries=20",
- "fail_causes=8|27|28|29|30|32|33|35|50|51|111|-5|-6|65537|65538|-3|2252|"
- + "2253|2254, maximum_retries=0", // No retry for those causes
+ // Permanent fail causes. When setup data call fails with the following
+ // fail causes, telephony data frameworks will stop timer-based retry on
+ // the failed APN until power cycle, APM, or some special events. Note that
+ // even timer-based retry is not performed, condition-based (RAT changes,
+ // registration state changes) retry can still happen.
+ "permanent_fail_causes=8|27|28|29|30|32|33|35|50|51|111|-5|-6|65537|65538|"
+ + "-3|65543|65547|2252|2253|2254, retry_interval=2500",
"capabilities=mms|supl|cbs, retry_interval=2000",
"capabilities=internet|enterprise|dun|ims|fota, retry_interval=2500|3000|"
+ "5000|10000|15000|20000|40000|60000|120000|240000|"
@@ -9474,6 +9512,8 @@
sDefaults.putLong(
KEY_PREMIUM_CAPABILITY_PURCHASE_CONDITION_BACKOFF_HYSTERESIS_TIME_MILLIS_LONG,
TimeUnit.MINUTES.toMillis(30));
+ sDefaults.putLong(KEY_PREMIUM_CAPABILITY_NETWORK_SETUP_TIME_MILLIS_LONG,
+ TimeUnit.MINUTES.toMillis(5));
sDefaults.putString(KEY_PREMIUM_CAPABILITY_PURCHASE_URL_STRING, null);
sDefaults.putBoolean(KEY_PREMIUM_CAPABILITY_SUPPORTED_ON_LTE_BOOL, false);
sDefaults.putStringArray(KEY_IWLAN_HANDOVER_POLICY_STRING_ARRAY, new String[]{
diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java
index d670e55..1f301c1 100644
--- a/telephony/java/android/telephony/SmsManager.java
+++ b/telephony/java/android/telephony/SmsManager.java
@@ -2268,7 +2268,21 @@
RESULT_RIL_SIM_ABSENT,
RESULT_RIL_SIMULTANEOUS_SMS_AND_CALL_NOT_ALLOWED,
RESULT_RIL_ACCESS_BARRED,
- RESULT_RIL_BLOCKED_DUE_TO_CALL
+ RESULT_RIL_BLOCKED_DUE_TO_CALL,
+ RESULT_RIL_GENERIC_ERROR,
+ RESULT_RIL_INVALID_RESPONSE,
+ RESULT_RIL_SIM_PIN2,
+ RESULT_RIL_SIM_PUK2,
+ RESULT_RIL_SUBSCRIPTION_NOT_AVAILABLE,
+ RESULT_RIL_SIM_ERROR,
+ RESULT_RIL_INVALID_SIM_STATE,
+ RESULT_RIL_NO_SMS_TO_ACK,
+ RESULT_RIL_SIM_BUSY,
+ RESULT_RIL_SIM_FULL,
+ RESULT_RIL_NO_SUBSCRIPTION,
+ RESULT_RIL_NO_NETWORK_FOUND,
+ RESULT_RIL_DEVICE_IN_USE,
+ RESULT_RIL_ABORTED
})
@Retention(RetentionPolicy.SOURCE)
public @interface Result {}
@@ -2534,7 +2548,7 @@
public static final int RESULT_RIL_SIM_ABSENT = 120;
/**
- * 1X voice and SMS are not allowed simulteneously.
+ * 1X voice and SMS are not allowed simultaneously.
*/
public static final int RESULT_RIL_SIMULTANEOUS_SMS_AND_CALL_NOT_ALLOWED = 121;
@@ -2553,6 +2567,73 @@
*/
public static final int RESULT_RIL_GENERIC_ERROR = 124;
+ /**
+ * A RIL internal error when one of the RIL layers receives an unrecognized response from a
+ * lower layer.
+ */
+ public static final int RESULT_RIL_INVALID_RESPONSE = 125;
+
+ /**
+ * Operation requires SIM PIN2 to be entered
+ */
+ public static final int RESULT_RIL_SIM_PIN2 = 126;
+
+ /**
+ * Operation requires SIM PUK2 to be entered
+ */
+ public static final int RESULT_RIL_SIM_PUK2 = 127;
+
+ /**
+ * Fail to find CDMA subscription from specified location
+ */
+ public static final int RESULT_RIL_SUBSCRIPTION_NOT_AVAILABLE = 128;
+
+ /**
+ * Received error from SIM card
+ */
+ public static final int RESULT_RIL_SIM_ERROR = 129;
+
+ /**
+ * Cannot process the request in current SIM state
+ */
+ public static final int RESULT_RIL_INVALID_SIM_STATE = 130;
+
+ /**
+ * ACK received when there is no SMS to ack
+ */
+ public static final int RESULT_RIL_NO_SMS_TO_ACK = 131;
+
+ /**
+ * SIM is busy
+ */
+ public static final int RESULT_RIL_SIM_BUSY = 132;
+
+ /**
+ * The target EF is full
+ */
+ public static final int RESULT_RIL_SIM_FULL = 133;
+
+ /**
+ * Device does not have subscription
+ */
+ public static final int RESULT_RIL_NO_SUBSCRIPTION = 134;
+
+ /**
+ * Network cannot be found
+ */
+ public static final int RESULT_RIL_NO_NETWORK_FOUND = 135;
+
+ /**
+ * Operation cannot be performed because the device is currently in use
+ */
+ public static final int RESULT_RIL_DEVICE_IN_USE = 136;
+
+ /**
+ * Operation aborted
+ */
+ public static final int RESULT_RIL_ABORTED = 137;
+
+
// SMS receiving results sent as a "result" extra in {@link Intents.SMS_REJECTED_ACTION}
/**
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index ef693b5..76a145c 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -4002,6 +4002,10 @@
* cautiously, for example, after formatting the number to a consistent format with
* {@link android.telephony.PhoneNumberUtils#formatNumberToE164(String, String)}.
*
+ * <p>The availability and correctness of the phone number depends on the underlying source
+ * and the network etc. Additional verification is needed to use this number for
+ * security-related or other sensitive scenarios.
+ *
* @param subscriptionId the subscription ID, or {@link #DEFAULT_SUBSCRIPTION_ID}
* for the default one.
* @return the phone number, or an empty string if not available.
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index ff1b1c0..35b2055 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -9476,7 +9476,8 @@
ALLOWED_NETWORK_TYPES_REASON_USER,
ALLOWED_NETWORK_TYPES_REASON_POWER,
ALLOWED_NETWORK_TYPES_REASON_CARRIER,
- ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G
+ ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G,
+ ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS,
})
@Retention(RetentionPolicy.SOURCE)
public @interface AllowedNetworkTypesReason {
@@ -9515,6 +9516,15 @@
public static final int ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G = 3;
/**
+ * To indicate allowed network type change is requested by an update to the
+ * {@link android.os.UserManager.DISALLOW_CELLULAR_2G} user restriction.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS = 4;
+
+ /**
* Set the allowed network types of the device and provide the reason triggering the allowed
* network change.
* <p>Requires permission: android.Manifest.MODIFY_PHONE_STATE or
@@ -9606,6 +9616,7 @@
case TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_POWER:
case TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_CARRIER:
case TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G:
+ case ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS:
return true;
}
return false;
@@ -17195,7 +17206,13 @@
}
/**
- * Purchase premium capability request was successful. Subsequent attempts will return
+ * Purchase premium capability request was successful.
+ * Once the purchase result is successful, the network must set up a slicing configuration
+ * for the purchased premium capability within the timeout specified by
+ * {@link CarrierConfigManager#KEY_PREMIUM_CAPABILITY_NETWORK_SETUP_TIME_MILLIS_LONG}.
+ * During the setup time, subsequent attempts will return
+ * {@link #PURCHASE_PREMIUM_CAPABILITY_RESULT_PENDING_NETWORK_SETUP}.
+ * After setup is complete, subsequent attempts will return
* {@link #PURCHASE_PREMIUM_CAPABILITY_RESULT_ALREADY_PURCHASED} until the booster expires.
* The expiry time is determined by the type or duration of boost purchased from the carrier,
* provided at {@link CarrierConfigManager#KEY_PREMIUM_CAPABILITY_PURCHASE_URL_STRING}.
@@ -17319,6 +17336,16 @@
public static final int PURCHASE_PREMIUM_CAPABILITY_RESULT_NOT_DEFAULT_DATA = 14;
/**
+ * Purchase premium capability was successful and is waiting for the network to setup the
+ * slicing configuration. If the setup is complete within the time specified by
+ * {@link CarrierConfigManager#KEY_PREMIUM_CAPABILITY_NETWORK_SETUP_TIME_MILLIS_LONG},
+ * subsequent requests will return {@link #PURCHASE_PREMIUM_CAPABILITY_RESULT_ALREADY_PURCHASED}
+ * until the purchase expires. If the setup is not complete within the time specified above,
+ * applications can reques the premium capability again.
+ */
+ public static final int PURCHASE_PREMIUM_CAPABILITY_RESULT_PENDING_NETWORK_SETUP = 15;
+
+ /**
* Results of the purchase premium capability request.
* @hide
*/
@@ -17336,7 +17363,8 @@
PURCHASE_PREMIUM_CAPABILITY_RESULT_FEATURE_NOT_SUPPORTED,
PURCHASE_PREMIUM_CAPABILITY_RESULT_NETWORK_NOT_AVAILABLE,
PURCHASE_PREMIUM_CAPABILITY_RESULT_NETWORK_CONGESTED,
- PURCHASE_PREMIUM_CAPABILITY_RESULT_NOT_DEFAULT_DATA})
+ PURCHASE_PREMIUM_CAPABILITY_RESULT_NOT_DEFAULT_DATA,
+ PURCHASE_PREMIUM_CAPABILITY_RESULT_PENDING_NETWORK_SETUP})
public @interface PurchasePremiumCapabilityResult {}
/**
@@ -17377,6 +17405,8 @@
return "NETWORK_CONGESTED";
case PURCHASE_PREMIUM_CAPABILITY_RESULT_NOT_DEFAULT_DATA:
return "NOT_DEFAULT_DATA";
+ case PURCHASE_PREMIUM_CAPABILITY_RESULT_PENDING_NETWORK_SETUP:
+ return "PENDING_NETWORK_SETUP";
default:
return "UNKNOWN (" + result + ")";
}
diff --git a/telephony/java/android/telephony/ims/ImsService.java b/telephony/java/android/telephony/ims/ImsService.java
index e8642fe..a3cbb4a 100644
--- a/telephony/java/android/telephony/ims/ImsService.java
+++ b/telephony/java/android/telephony/ims/ImsService.java
@@ -458,8 +458,8 @@
}
}
- private IImsRcsFeature createRcsFeatureInternal(int slotId, int subI) {
- RcsFeature f = createRcsFeatureForSubscription(slotId, subI);
+ private IImsRcsFeature createRcsFeatureInternal(int slotId, int subId) {
+ RcsFeature f = createRcsFeatureForSubscription(slotId, subId);
if (f != null) {
f.setDefaultExecutor(getCachedExecutor());
setupFeature(f, slotId, ImsFeature.FEATURE_RCS);
diff --git a/telephony/java/android/telephony/ims/feature/ImsFeature.java b/telephony/java/android/telephony/ims/feature/ImsFeature.java
index f5b158f..a42327b 100644
--- a/telephony/java/android/telephony/ims/feature/ImsFeature.java
+++ b/telephony/java/android/telephony/ims/feature/ImsFeature.java
@@ -394,10 +394,12 @@
@VisibleForTesting
public void addImsFeatureStatusCallback(@NonNull IImsFeatureStatusCallback c) {
try {
- // If we have just connected, send queued status.
- c.notifyImsFeatureStatus(getFeatureState());
- // Add the callback if the callback completes successfully without a RemoteException.
- mStatusCallbacks.register(c);
+ synchronized (mStatusCallbacks) {
+ // Add the callback if the callback completes successfully without a RemoteException
+ mStatusCallbacks.register(c);
+ // If we have just connected, send queued status.
+ c.notifyImsFeatureStatus(getFeatureState());
+ }
} catch (RemoteException e) {
Log.w(LOG_TAG, "Couldn't notify feature state: " + e.getMessage());
}
@@ -409,7 +411,9 @@
*/
@VisibleForTesting
public void removeImsFeatureStatusCallback(@NonNull IImsFeatureStatusCallback c) {
- mStatusCallbacks.unregister(c);
+ synchronized (mStatusCallbacks) {
+ mStatusCallbacks.unregister(c);
+ }
}
/**
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index 9892671..9f612e6 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -536,6 +536,12 @@
int RIL_REQUEST_TRIGGER_EMERGENCY_NETWORK_SCAN = 230;
int RIL_REQUEST_CANCEL_EMERGENCY_NETWORK_SCAN = 231;
int RIL_REQUEST_EXIT_EMERGENCY_MODE = 232;
+ int RIL_REQUEST_SET_SRVCC_CALL_INFO = 233;
+ int RIL_REQUEST_UPDATE_IMS_REGISTRATION_INFO = 234;
+ int RIL_REQUEST_START_IMS_TRAFFIC = 235;
+ int RIL_REQUEST_STOP_IMS_TRAFFIC = 236;
+ int RIL_REQUEST_SEND_ANBR_QUERY = 237;
+ int RIL_REQUEST_TRIGGER_EPS_FALLBACK = 238;
/* Responses begin */
int RIL_RESPONSE_ACKNOWLEDGEMENT = 800;
@@ -607,4 +613,7 @@
int RIL_UNSOL_REGISTRATION_FAILED = 1104;
int RIL_UNSOL_BARRING_INFO_CHANGED = 1105;
int RIL_UNSOL_EMERGENCY_NETWORK_SCAN_RESULT = 1106;
+ int RIL_UNSOL_TRIGGER_IMS_DEREGISTRATION = 1107;
+ int RIL_UNSOL_CONNECTION_SETUP_FAILURE = 1108;
+ int RIL_UNSOL_NOTIFY_ANBR = 1109;
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdFromIcon.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdFromIcon.kt
index 73e6d22..5e6fc21 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdFromIcon.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdFromIcon.kt
@@ -19,11 +19,11 @@
import android.platform.test.annotations.FlakyTest
import android.platform.test.annotations.RequiresDevice
import android.view.Surface
+import android.view.WindowManagerPolicyConstants
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.rules.RemoveAllTasksButHomeRule
import org.junit.FixMethodOrder
import org.junit.Test
@@ -68,7 +68,6 @@
tapl.setExpectedRotation(Surface.ROTATION_0)
}
RemoveAllTasksButHomeRule.removeAllTasksButHome()
- this.setRotation(testSpec.startRotation)
}
transitions {
tapl
@@ -187,7 +186,13 @@
@Parameterized.Parameters(name = "{0}")
@JvmStatic
fun getParams(): Collection<FlickerTestParameter> {
- return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests()
+ return FlickerTestParameterFactory.getInstance()
+ // TAPL fails on landscape mode b/240916028
+ .getConfigNonRotationTests(
+ supportedNavigationModes = listOf(
+ WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY
+ )
+ )
}
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationCold.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationCold.kt
index 09d7637..0edbc86 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationCold.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationCold.kt
@@ -97,8 +97,8 @@
super.statusBarLayerPositionAtEnd()
/** {@inheritDoc} */
- @Postsubmit
@Test
+ @Ignore("Not applicable to this CUJ. Display starts locked and app is full screen at the end")
override fun navBarLayerIsVisibleAtStartAndEnd() = super.navBarLayerIsVisibleAtStartAndEnd()
/** {@inheritDoc} */
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWithLockOverlayApp.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWithLockOverlayApp.kt
index c10b993..4ee1283 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWithLockOverlayApp.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWithLockOverlayApp.kt
@@ -16,6 +16,7 @@
package com.android.server.wm.flicker.launch
+import android.platform.test.annotations.FlakyTest
import android.platform.test.annotations.Postsubmit
import android.platform.test.annotations.Presubmit
import android.platform.test.annotations.RequiresDevice
@@ -71,7 +72,7 @@
}
@Test
- @Postsubmit
+ @FlakyTest(bugId = 227143265)
fun showWhenLockedAppWindowBecomesVisible() {
testSpec.assertWm {
this.hasNoVisibleAppWindow()
@@ -83,7 +84,7 @@
}
@Test
- @Postsubmit
+ @FlakyTest(bugId = 227143265)
fun showWhenLockedAppLayerBecomesVisible() {
testSpec.assertLayers {
this.isInvisible(showWhenLockedApp)
@@ -98,11 +99,17 @@
@Presubmit @Test override fun appLayerBecomesVisible() = super.appLayerBecomesVisible()
/** {@inheritDoc} */
- @Postsubmit
+ @FlakyTest(bugId = 227143265)
@Test
override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
super.visibleLayersShownMoreThanOneConsecutiveEntry()
+ /** {@inheritDoc} */
+ @FlakyTest(bugId = 209599395)
+ @Test
+ override fun navBarLayerIsVisibleAtStartAndEnd() =
+ super.navBarLayerIsVisibleAtStartAndEnd()
+
companion object {
/**
* Creates the test configurations.